Socket的网络通信编程

实际工作中,基于Socket的网络通信应用非常广泛,本人写了个源码,小试牛刀,实现的功能如下:

1,模拟一个服务端和多个客户端进行交互;
2,在客户端可将一个java对象进行序列化,并发送给服务端;
3,服务端接收到客户端发送过来的序列化对象后,进行反系列化


设计思路是:

   使用套接字实现基于TCP协议的服务器和客户机程序   

   依据TCP协议,在B/S架构的通讯过程中,客户端和服务器的Socket动作如下:


客户端:

1.用服务器的IP地址和端口号实例化Socket对象。

2.调用connect方法,连接到服务器上。

3.将实体对象序列化后发送到服务器的IO流填充到IO对象里,如ObjectOutputStream。

4.利用Socket提供的getOutputStream方法,通过IO流对象,向服务器发送数据流。

5. 通讯完成后,关闭打开的IO对象和Socket


服务器端:

1、在服务器,用一个端口来实例化一个 ServerSocket对象。此时,服务器就可以在这个端口时刻监听从客户端发来的连接请求。 

2、调用ServerSocket的accept方法,开始监听连接从端口上发来的连接请求。

3利用accept方法返回的客户端的Socket对象,进行读写IO的操作。

4、利用IO流对象中的ObjectInputStream封装Socket对象提供的getInputStream方法,反序列化实体对象。

5、通讯完成后,关闭打开的流和Socket对象。


相关性能优化方案:

在服务器端利用多线程实现客户端和服务器的通信,当Server端接受到一个Client连接请求之后,就把处理流程放到一个独立的子线程里去运行,然后等待下一个Client连接请求,这样就不会阻塞Server端接收请求了。每个独立运行的程序在使用完Socket对象之后将其关闭,并结束该条子线程。(子线程用内部类封装起来)

源码如下:

1.客户端程序

package test.socket;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;


/**
 * 客户端,对象系列化 后传输到服务器端
 * @author Administrator
 *
 */
public class SocketClient {

	private final static Logger logger = Logger.getLogger(SocketClient.class.getName());

	public static void main(String[] args) throws Exception {
		
		for (int i = 0; i < 5; i++) {
			Socket socket = null;
			ObjectOutputStream os = null;
			try {
				socket = new Socket("localhost", 30000);   //此处绑定的ip地址应该根据具体服务器的地址来填写。

				os = new ObjectOutputStream(socket.getOutputStream());
				User user = new User("user_" + i, "password_" + i);
				os.writeObject(user);
				os.flush();
		
			} catch (IOException ex) {
				logger.log(Level.SEVERE, null, ex);
			} finally {
				try {
					os.close();
				} catch (Exception ex) {
				}
				try {
					socket.close();
				} catch (Exception ex) {
				}
			}
		}
	}

}

2.服务器端程序

package test.socket;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Logger;


/**
 * 服务器期端接收 客户端传过来的序列化对象 并反序列化
 * @author Administrator
 *
 */
public class SocketService {
	
	 private final static Logger logger = Logger.getLogger(SocketService.class.getName());  
	 private ServerSocket server;
		 
	 /**
	  * 监听服务器端的 30000端口
	  * @throws IOException
	  */
	 public void start() throws IOException
	 {
//		    String hostIP = InetAddress.getLocalHost().getHostAddress() ;  //服务器上的地址
//	        logger.info("服务器端hostIP---------------->" + hostIP);
		 
	        InetAddress iAddress = InetAddress.getByName("localhost");
	        server = new ServerSocket(30000, 50, iAddress);  // 监听30000端口,等待请求通过网络传入
	 }
	 
	 /**
	  * 与客户端建立连接(多线程并发控制)
	  */
	 private void accept()
	 {
		 //启动线程
		 new Thread()
		 {
			 @Override
			 public void run()
			 {
				 while (true) //监听端口需要一个死循环,来实现24小时不间隔运行
	                {
	                    try
	                    {
	                        logger.info("监听客户端accept.....");
	                        Socket socket = server.accept(); //侦听并接受客户端连接,
	                        socket.setOOBInline(true); //
	                        socket.setTcpNoDelay(true);
	                        logger.info("new client......" );
	                        processRequest(socket);  //一个客户端连接用一个线程来处理,处理完该线程就结束。
	                    }
	                    catch (IOException e)
	                    {
	                        e.printStackTrace();
	                    }
	                } 
			 }
		 }.start();	 
	 }
	 
	 
	 /**
	  * 实现客户端套接字
	  * @param socket
	  */
	 private void processRequest(Socket socket)
	 {
		 new RequestProcessor(socket).start(); //用内部类处理客户端的业务请求(好处?可以让jvm回收相关的子线程,并很好的隐藏了内部逻辑)
	 }
	 
	 
	 /**
	  * 实现具体业务逻辑的内部类
	  * @author Administrator *
	  */
	 private class RequestProcessor extends Thread
	 {
		 Socket socket;
		 
		 //用内部类构造方法初始化线程
		 public RequestProcessor(Socket socket)
		 {
			 super();  
			 this.socket = socket ; 
		 }
		 
		 @Override
		 public void run() 
		 {
			 try 
			 {
				ObjectInputStream is = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));  
			    
                Object obj = is.readObject();  
                if (obj != null) {  
                	User user = (User)obj;  
                    logger.info("反序列化user: " + user.getName() + "/" + user.getPassword());  
                }
			 } 
			 catch (Exception e)
			 {
				e.printStackTrace();
			 }
		 } 	 
		 
	 }

	 
	 /**
	  * 服务器端hostIP的 接口服务
	  */
	 public static void startServer()
	 {
		 try
		 {
			 SocketService socketService = new SocketService();  //因为静态方法不能直接调用非静态方法
			 
			 socketService.start(); 
			 socketService.accept();	 
		 }
		 catch(IOException e)
		 {
			 e.printStackTrace();
		 }
		 
	 }
	 
	 /**
	  * 启动服务器端服务
	  * @param args
	  * @throws IOException
	  */
	 public static void main(String[] args) throws IOException
	 {
	        startServer();
	 }
	 
}

3.待序列化 和 反序列化的 实体类

package test.socket;


/**
 * 待序列化传输的对象
 * @author Administrator
 *
 */
public class User implements java.io.Serializable 
{  

    private static final long serialVersionUID = 1L;  
    private String name;  
    private String password;  
  
    public User() {  
          
    }  
      
    public User(String name, String password) {  
        this.name = name;  
        this.password = password;  
    }  
      
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public String getPassword() {  
        return password;  
    }  
  
    public void setPassword(String password) {  
        this.password = password;  
    }  
    
    
}

代码运行解释:

已测试通过,先运行SocketService类,再运行SocketClient类,就可以在SocketService的控制台端看见分别接收处理每个Client的请求了(注:在SocketClient的控制台是看不到的)










你可能感兴趣的:(Socket的网络通信)