實際工做中,基於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的控制檯是看不到的)