Socket的網絡通訊編程

實際工做中,基於Socket的網絡通訊應用很是普遍,本人寫了個源碼,小試牛刀,實現的功能以下: java

1,模擬一個服務端和多個客戶端進行交互;
2,在客戶端可將一個java對象進行序列化,併發送給服務端;
3,服務端接收到客戶端發送過來的序列化對象後,進行反系列化性能優化


設計思路是: 服務器

   使用套接字實現基於TCP協議的服務器和客戶機程序    網絡

   依據TCP協議,在B/S架構的通信過程當中,客戶端和服務器的Socket動做以下: 多線程


客戶端: 架構

1.用服務器的IP地址和端口號實例化Socket對象。 併發

2.調用connect方法,鏈接到服務器上。 jvm

3.將實體對象序列化後發送到服務器的IO流填充到IO對象裏,如ObjectOutputStream。 socket

4.利用Socket提供的getOutputStream方法,經過IO流對象,向服務器發送數據流。 ide

5. 通信完成後,關閉打開的IO對象和Socket


服務器端:

一、在服務器,用一個端口來實例化一個 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的控制檯是看不到的)
相關文章
相關標籤/搜索