轉自 http://blog.csdn.net/ooppookid/article/details/51711323
1、如何編寫多線程Socket程序
了解Socket看這里:Socket是什么
多線程Socket與單線程類似,只是使用了多線程的方式來管理連接,主線程負責接收連接,在接到連接后變創建新的線程,每個線程負責與自己的客戶端進行通信。
了解單線程Socket看這里:如何編寫單多線程Socket程序
與單線程Socket例子相比來說,服務端可以與多個客戶端進行通信了,不過多線程頻繁的創建與銷毀便會帶來很大的資源開銷,而系統的網絡資源等都是有限的。因此一般會引入線程池,可以在某種程度上重用線程,減少線程的創建和銷毀的次數以減少開銷。
我們的代碼也分為客戶端和服務端兩部分。服務端的代碼中包含了使用和不使用線程池的兩種方式。
服務端代碼:
?1?
import?java.io.BufferedReader;
?2?
import?java.io.IOException;
?3?
import?java.io.InputStreamReader;
?4?
import?java.io.PrintWriter;
?5?
import?java.net.ServerSocket;
?6?
import?java.net.Socket;
?7?
import?java.util.concurrent.ExecutorService;
?8?
import?java.util.concurrent.Executors;
?9?
10?
public?class?SocketThreadPoolDemoServer?{
11?
12?
????private?int?port?=?8000;
13?
14?
????private?ServerSocket?serverSocket;
15?
16?
????private?ExecutorService?executorService;?//?連接池
17?
18?
????private?final?int?POOL_SIZE?=?1;?//?連接池大小?,?若為?1?時最多支持?2?線程
19?
20?
????public?SocketThreadPoolDemoServer()?throws?Exception?{
21?
????????serverSocket?=?new?ServerSocket(port);
22?
????????executorService?=?Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()?*?POOL_SIZE);//?初始化線程池
23?
????????System.out.println("waitting?connet
");
24?
25?
????}
26?
27?
????/**
28?
?????*
29?
?????*?接受連接
30?
?????*
31?
?????*?@author?sunjie?at?2016年6月14日
32?
?????*
33?
?????*/
34?
????public?void?service()?{
35?
????????Socket?socket?=?null;
36?
????????while?(true)?{
37?
????????????try?{
38?
????????????????socket?=?serverSocket.accept();
39?
????????????????executorService.execute(new?Handler(socket));?//?使用連接池
40?
????????????????//?new?Thread(new?Handler(socket)).start();//?不使用連接池
41?
????????????}?catch?(IOException?e)?{
42?
????????????????e.printStackTrace();
43?
????????????}
44?
????????}
45?
????}
46?
47?
????/**
48?
?????*
49?
?????*?線程類,負責維持與一個客戶端的通信
50?
?????*
51?
?????*?@author?sunjie?at?2016年6月14日
52?
?????*
53?
?????*/
54?
????class?Handler?implements?Runnable?{
55?
56?
????????private?Socket?socket?=?null;
57?
58?
????????public?Handler(Socket?socket)?{
59?
????????????this.socket?=?socket;
60?
????????}
61?
62?
????????@Override
63?
????????public?void?run()?{
64?
????????????System.out.println("new?connection?accepted:"?+?socket.getInetAddress()?+?":"?+?socket.getPort());
65?
????????????try?{
66?
????????????????BufferedReader?reader?=?new?BufferedReader(new?InputStreamReader(socket.getInputStream(),?"UTF-8"));
67?
????????????????PrintWriter?writer?=?new?PrintWriter(socket.getOutputStream());
68?
????????????????String?msg?=?null;
69?
????????????????while?((msg?=?reader.readLine())?!=?null)?{
70?
????????????????????System.out.println("from?"?+?socket.getInetAddress()?+?":"?+?socket.getPort()?+?",?receive?msg:"
71?
????????????????????????????+?msg);
72?
????????????????????writer.println(msg);
73?
????????????????????writer.flush();
74?
????????????????????if?("close".equals(msg))?{
75?
????????????????????????break;
76?
????????????????????}
77?
????????????????}
78?
????????????}?catch?(IOException?e)?{
79?
????????????????e.printStackTrace();
80?
????????????}?finally?{
81?
????????????????try?{
82?
????????????????????if?(socket?!=?null)?{
83?
????????????????????????socket.close();
84?
????????????????????}
85?
????????????????}?catch?(IOException?e)?{
86?
????????????????????e.printStackTrace();
87?
????????????????}
88?
????????????}
89?
????????}
90?
????}
91?
92?
????public?static?void?main(String[]?args)?throws?Exception?{
93?
????????new?SocketThreadPoolDemoServer().service();
94?
????}
95?
}
96?
97?
運行服務端代碼后,程序會一直進行監聽,直到接收到客戶端請求為止。結果如下:
waitting connet…
客戶端代碼(與單線程完全相同):
?1?public?class?SocketDemoClient?{
?2?
?3?????private?String?host?=?"127.0.0.1";//?要發送給服務端的ip
?4?
?5?????private?int?port?=?8000;//?要發送給服務端的端口
?6?
?7?????private?Socket?socket;
?8?
?9?????public?SocketDemoClient()?throws?Exception?{
10?????????socket?=?new?Socket(host,?port);//?構造Socket客戶端,并與連接服務端
11?????}
12?
13?????public?void?talk()?throws?IOException?{
14?????????try?{
15?????????????BufferedReader?reader?=?new?BufferedReader(new?InputStreamReader(socket.getInputStream(),?"UTF-8"));
16?????????????PrintWriter?writer?=?new?PrintWriter(socket.getOutputStream());
17?????????????//?讀取本地控制臺的消息
18?????????????BufferedReader?localReader?=?new?BufferedReader(new?InputStreamReader(System.in));
19?????????????String?msg?=?null;
20?????????????while?((msg?=?localReader.readLine())?!=?null)?{
21?????????????????writer.println(msg);
22?????????????????writer.flush();
23?????????????????System.out.println("send?msg:"?+?reader.readLine());
24?????????????????if?("close".equals(msg))?{
25?????????????????????break;
26?????????????????}
27?????????????}
28?????????}?catch?(Exception?e)?{
29?????????????e.printStackTrace();
30?????????}?finally?{
31?????????????if?(socket?!=?null)?{
32?????????????????socket.close();
33?????????????}
34?????????}
35?????}
36?
37?????public?static?void?main(String[]?args)?throws?Exception?{
38?????????new?SocketDemoClient().talk();
39?????}
40?}
由于我們要測試多個客戶端連接同一個服務端,所以我們需要多次運行客戶端代碼。這里我們運行兩次之后(稱為客戶端1、客戶端2),查看服務端的Console,會出現以下結果,說明已經連接成功:
waitting connet…
new connection accepted:/127.0.0.1:59593
new connection accepted:/127.0.0.1:59596
我們在去客戶端1的Console中輸入我們要發送的消息”維護世界和平”,回車確定后,客戶端1的Console出現以下結果,消息已經發出:
send msg:維護世界和平
再去客戶端2的Console中輸入”好好學習天天向上”,回車確定后,客戶端2的Console出現以下結果,消息已經發出:
send msg:好好學習天天向上
在服務端的Console中,我們會看到如下結果,說明兩個客戶端的消息已經被接受:
waitting connet…
new connection accepted:/127.0.0.1:59593
new connection accepted:/127.0.0.1:59596
from /127.0.0.1:59593, receive msg:維護世界和平
from /127.0.0.1:59596, receive msg:好好學習天天向上