Socket TCP 協議實現服務端和客戶端的簡單通訊-結合線程池的使用
阿新 • • 發佈:2018-11-07
文章目錄
前言
沒啥說的,就是記錄一下程式碼,方便以後檢視
對了,本篇客戶端邏輯中有一個製造慢服務的 thread.sleep ,模擬客戶端很慢很慢對情況
服務端和客戶端都使用了執行緒池
當前模式的弊端
網路通訊目前流行 NIO 模式,將網路IO 等待時間從業務處理執行緒中抽離出來。本文並沒有體現 NIO,當客戶端是一個長連線當時候,伺服器資源就會被佔用——等待戈多(客戶端傳送資料)。
服務端程式碼
啟動 main 方法,服務端啟動,注意是 while(true)哦
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 使用執行緒池實現 Socket 服務端 處理 Socket 請求
* @author jie.wu
*
*/
public class ConcurentSocketServer {
private static ExecutorService threadPool = Executors.newCachedThreadPool();
/**
* 處理客戶端請求的執行緒類
* */
static class HandleMsg implements Runnable {
// 客戶端套接字物件
private Socket clientSocket;
// 新增構造方法
public HandleMsg(Socket clientSocket) {
this.clientSocket = clientSocket;
}
@Override
public void run() {
// 獲取客戶端輸入流
InputStream inputStream = null;
OutputStream outputStream = null;
PrintWriter printWriter = null;
try {
// 開始時間
Long beginTime = System.currentTimeMillis();
//處理客戶端資訊
inputStream = clientSocket.getInputStream();
byte b[] = new byte[1024];
StringBuffer sbf = new StringBuffer();
for (int n; (n = inputStream.read(b)) != -1;) {
sbf.append(new String(b, 0, n));
}
clientSocket.shutdownInput();
// 向客戶端反饋資訊
outputStream = clientSocket.getOutputStream();
printWriter = new PrintWriter(outputStream);
printWriter.write("我是服務端");
printWriter.flush();
clientSocket.shutdownOutput();
// 結束時間
long endTime = System.currentTimeMillis();
System.out.println("耗時" + (endTime - beginTime) + "ms 客戶端傳遞進來的資訊為:" + sbf.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
// 關閉資源
try {
if (inputStream != null)
inputStream.close();
if (printWriter != null)
printWriter.close();
if (outputStream != null)
outputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
@SuppressWarnings("resource")
public static void main(String[] args) {
ServerSocket serverSocket = null;
Socket clientSocket = null;
try {
serverSocket = new ServerSocket(10000);
} catch (IOException e) {
e.printStackTrace();
}
// 對客戶端請求對處理
while (true) {
try {
clientSocket = serverSocket.accept();
// 使用多執行緒進行處理
threadPool.execute(new HandleMsg(clientSocket));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客戶端程式碼
也使用了執行緒池,同時模擬了客戶端慢呼叫,使用 thread.sleep 對傳送資訊過程進行了減速
執行main 方法,執行緒池將傳送10條請求
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 使用執行緒池實現 Socket 客戶端 傳送 Socket 請求
*
* @author jie.wu
*
*/
public class ConcurentSocketClient {
private static ExecutorService threadPool = Executors.newCachedThreadPool();
static class HandleMsg implements Runnable {
//記錄執行緒編號
private int threadNumber;
//重寫構造方法
public HandleMsg(int threadNumber) {
this.threadNumber = threadNumber;
}
@Override
public void run() {
Socket socket = null;
OutputStream outputStream = null;
PrintWriter printWriter = null;
InputStream inputStream = null;
try {
socket = new Socket("127.0.0.1", 10000);
outputStream = socket.getOutputStream();
printWriter = new PrintWriter(outputStream);
printWriter.write("你好,");
// 客戶端睡眠
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
printWriter.write("我是客戶端" + threadNumber);
printWriter.flush();
socket.shutdownOutput();
// 獲取伺服器端返回的資訊
inputStream = socket.getInputStream();
byte b[] = new byte[1024];
StringBuffer sbf = new StringBuffer();
for (int n; (n = inputStream.read(b)) != -1;) {
sbf.append(new String(b, 0, n));
}
System.out.println("伺服器端反饋進來的資訊為:" + sbf.toString());
socket.shutdownInput();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 關閉資源
try {
if (printWriter != null)
printWriter.close();
if (outputStream != null)
outputStream.close();
if (inputStream != null)
inputStream.close();
if (socket != null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
threadPool.execute(new HandleMsg(i));
}
}
}
執行結果
客戶端
伺服器端反饋進來的資訊為:我是服務端
伺服器端反饋進來的資訊為:我是服務端
伺服器端反饋進來的資訊為:我是服務端
伺服器端反饋進來的資訊為:我是服務端
伺服器端反饋進來的資訊為:我是服務端
伺服器端反饋進來的資訊為:我是服務端
伺服器端反饋進來的資訊為:我是服務端
伺服器端反饋進來的資訊為:我是服務端
伺服器端反饋進來的資訊為:我是服務端
伺服器端反饋進來的資訊為:我是服務端
服務端
耗時1027ms 客戶端傳遞進來的資訊為:你好,我是客戶端4
耗時1028ms 客戶端傳遞進來的資訊為:你好,我是客戶端2
耗時1026ms 客戶端傳遞進來的資訊為:你好,我是客戶端6
耗時1030ms 客戶端傳遞進來的資訊為:你好,我是客戶端5
耗時1033ms 客戶端傳遞進來的資訊為:你好,我是客戶端0
耗時1033ms 客戶端傳遞進來的資訊為:你好,我是客戶端3
耗時1034ms 客戶端傳遞進來的資訊為:你好,我是客戶端1
耗時1032ms 客戶端傳遞進來的資訊為:你好,我是客戶端9
耗時1034ms 客戶端傳遞進來的資訊為:你好,我是客戶端8
耗時1036ms 客戶端傳遞進來的資訊為:你好,我是客戶端7
參考文獻
[1]、https://blog.csdn.net/bestcxx/article/details/73753649
[2]、《Java 高併發程式設計》 2016年8月