socket编程之obj压缩加密传输

本文介绍了Java中如何使用Socket进行对象的压缩和加密传输。通过实现Serializable接口的POJO对象,利用ObjectInputStream和ObjectOutputStream进行序列化和反序列化。在处理双向通信时,注意读写阻塞问题,并确保正确使用flush方法。此外,对比了BufferedReader和InputStreamReader的区别,以及在实际应用中如何结合GZIPInputStream和GZIPOutputStream处理大对象的压缩传输。文中还给出了服务器端和客户端的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于需要序列化这个对象以便在网络上传输,所以POJO必须要实现java.io.Serializable接口。使用了

ObjectInputStream和ObjectOutputStream来接收和发送socket中的InputStream和OutputStream,然

后转换成Java对象。

client与server之间socket双向通信,因此要注意io读写的阻塞问题。client在写完数据时要记得

flush一下,然后再读数据,服务端SocketInputStream中读取数据的操作也是阻塞式的,如果

从输入流中没有读取到数据程序会一直在那里不动,直到客户端Socket的输出流中写入了数据,

或关闭了Socket的输出流。

在读写object时用到了BufferedReader,下面是BufferedReader与InputReader区别

BufferedReader类

BufferedReader 由Reader类扩展而来,提供通用的缓冲方式文本读取,而且提供了很实用的readLine,

读取一个文本行,字符输入流中读取文本,缓冲各个字符,从而提供字符、数组和行的高效读取。


一般用法:
    
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("ming.txt")));
  String data = null;
  while((data = br.readLine())!=null)
  {
   System.out.println(data); 
  }


InputStreamReader 类

是字节流通向字符流的桥梁,封裝了InputStream在里头, 它以较高级的方式,一次读取一个一个字符以文本格

式输入 / 输出,可以指定编码格式;

一般用法:

InputStreamReader isr = new InputStreamReader(new FileInputStream("ming.txt"));
   while((ch = isr.read())!=-1)
   {
    System.out.print((char)ch); 
   }



服务器端代码


public class server {
	public static void main(String args[]) throws IOException{
		 //为了简单起见,所有的异常信息都往外抛  
		  int port = 8899;  
	      //定义一个ServerSocket监听在端口8899上  
	      ServerSocket server = new ServerSocket(port);  


	      while(true){
	    	
	    	  //server尝试接收其他Socket的连接请求,server的accept方法是阻塞式的  
	    	  Socket socket=server.accept();
	    	  
	    	  //每接收到一个Socket就建立一个新的线程来处理它  
	    	  new Thread(new Task(socket)).start();
	      }
	}
	 static class Task implements Runnable{
	//静态内部类
		 
		private Socket socket;
		
		public Task(Socket socket){
			this.socket=socket;
		}
		
		
		@Override
		public void run() {
			ObjectInputStream oi = null;
			ObjectOutputStream oo = null;
			try{
				handleSocket(oi,oo);
			}
			catch(Exception e){
				e.printStackTrace();
			}
			finally{
				try {
					oi.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				try {
					oo.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				try {
					socket.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
		private void handleSocket(ObjectInputStream oi,ObjectOutputStream oo) throws Exception{
			 //跟客户端建立好连接之后,我们就可以获取socket的InputStream,并从中读取客户端发过来的信息了。  
			oi=new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
			//获取obj
			Object obj= oi.readObject();
			ShopInfo shopInfo=(ShopInfo)obj;
			
			System.out.println("from client: " + shopInfo.getShopName());
			
			//获取输出流
			oo=new ObjectOutputStream(socket.getOutputStream());
			
			shopInfo.setShopName("东山再起");
			//写对象
			oo.writeObject(shopInfo);
			//冲一下,从缓冲区写入
			oo.flush();
		}


	}


}


客户端代码


public class client {
	 public static void main(String args[]) throws Exception {  
		 
	      //为了简单起见,所有的异常都直接往外抛  
		 String host = "192.168.1.134";  //要连接的服务端IP地址  
	      int port = 8899;   //要连接的服务端对应的监听端口  
	      //与服务端建立连接  
	      Socket client = new Socket(host, port);  
	      //建立连接后就可以往服务端写数据了  
	      ObjectOutputStream os = new ObjectOutputStream(client.getOutputStream());  
           
          ShopInfo shopInfo=new ShopInfo();
          shopInfo.setShopName("雷霆万钧");
          os.writeObject(shopInfo);  
          os.flush();  
          ObjectInputStream is = new ObjectInputStream(new BufferedInputStream(client.getInputStream())); 
          Object obj= is.readObject();
          if(obj != null){
        	  ShopInfo shop=(ShopInfo)obj;
              System.out.println("from server: " + shop.getShopName());
          }
          is.close();
          os.close();
	      client.close();  
	   }  
}



POJO实体


public class ShopInfo extends Serializable{
	private static final long serialVersionUID = 1L;
	

	/**
	 * 店铺名称
	 */
	private String shopName;

	public void setShopName(String shopName){
		this.shopName = shopName;
	}

	public String getShopName(){
		return this.shopName;
	}
}


运行结果如图








在有些情况下比如网络环境不好或者对象比较大的情况下需要把数据对象进行压缩然后在传输,此时就需要压缩这些

对象流,此时就可以GZIPInputStream和GZIPOutputStream来处理一下socket的InputStream和OutputStream。

仍然需要一个实现了java.io.Serializable接口的简单Java对象。下面为代码示例】

服务器端代码

public class server {
	public static void main(String args[]) throws IOException{
		 //为了简单起见,所有的异常信息都往外抛  
		  int port = 8899;  
	      //定义一个ServerSocket监听在端口8899上  
	      ServerSocket server = new ServerSocket(port);  

	      while(true){
	    	
	    	  //server尝试接收其他Socket的连接请求,server的accept方法是阻塞式的  
	    	  Socket socket=server.accept();
	    	  
	    	  //每接收到一个Socket就建立一个新的线程来处理它  
	    	  new Thread(new Task(socket)).start();
	      }
	}
	 static class Task implements Runnable{
	//静态内部类
		 
		private Socket socket;
		
		public Task(Socket socket){
			this.socket=socket;
		}
		
		
		@Override
		public void run() {
			ObjectInputStream oi = null;
			ObjectOutputStream oo = null;
			try{
				handleSocket(oi,oo);
			}
			catch(Exception e){
				e.printStackTrace();
			}
			finally{
				try {
					oi.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				try {
					oo.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				try {
					socket.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
		private void handleSocket(ObjectInputStream oi,ObjectOutputStream oo) throws Exception{
			 //跟客户端建立好连接之后,我们就可以获取socket的InputStream,并从中读取客户端发过来的信息了。  
			//oi=new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
			GZIPInputStream gzipos=new GZIPInputStream(socket.getInputStream());
			oi=new ObjectInputStream(gzipos);
			//获取obj
			Object obj= oi.readObject();
			ShopInfo shopInfo=(ShopInfo)obj;
			
			System.out.println("from client: " + shopInfo.getShopName());
			
			//获取输出流
			oo=new ObjectOutputStream(socket.getOutputStream());
			
			shopInfo.setShopName("东山再起");
			//写对象
			oo.writeObject(shopInfo);
			//冲一下,从缓冲区写入
			oo.flush();
		}

	}

}
客户端代码


public class client {
	 public static void main(String args[]) throws Exception {  
		 
	      //为了简单起见,所有的异常都直接往外抛  
		 String host = "192.168.1.134";  //要连接的服务端IP地址  
	      int port = 8899;   //要连接的服务端对应的监听端口  
	      //与服务端建立连接  
	      Socket client = new Socket(host, port);  
	      //建立连接后就可以往服务端写数据了  
	      //ObjectOutputStream os = new ObjectOutputStream(client.getOutputStream());  
	      GZIPOutputStream gzipos = new GZIPOutputStream(client.getOutputStream());  
	      ObjectOutputStream os = new ObjectOutputStream(gzipos);  
	      ShopInfo shopInfo=new ShopInfo();
          shopInfo.setShopName("雷霆万钧");
          os.writeObject(shopInfo);  
          os.flush();  
          gzipos.finish();
          ObjectInputStream is = new ObjectInputStream(new BufferedInputStream(client.getInputStream())); 
          Object obj= is.readObject();
          if(obj != null){
        	  ShopInfo shop=(ShopInfo)obj;
              System.out.println("from server: " + shop.getShopName());
          }
          is.close();
          os.close();
          
	      client.close();  
	   }  
}

使用加密协议传输对象

对于一些有安全要求的应用就需要加密传输的数据,此时就需要用到SSLSocket了。这里需要用到ServerSocketFactory类来创建SSLServerSocket类实例,然后在通过SSLServerSocket来获取SSLSocket实例,这里考虑到面向对象中的面向接口编程的理念,所以代码中并没有出现SSLServerSocket和SSLSocket,而是用了他们的父类ServerSocket和Socket。在获取到ServerSocket和Socket实例以后,剩下的代码就和不使用加密方式一样了。

代码写完了,下面就需要产生keystore文件了,运行下面的命令
keytool -genkey -alias mysocket -keyalg RSA -keystore mysocket.jks  


在提示输入项中,密码项自己给定,其它都不改直接回车,这里我使用的密码是“123123”。

运行Server

java -Djavax.net.ssl.keyStore=mysocket.jks -Djavax.net.ssl.keyStorePassword=123123 com.test.garbagecan.test.socket.ssl.MyServer  


运行Client
java -Djavax.net.ssl.trustStore=mysocket.jks  -Djavax.net.ssl.trustStorePassword=123123 com.test.garbagecan.test.socket.ssl.MyClient  




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值