如何編寫多線程Socket程序
1、如何編寫多線程Socket程序
了解Socket看這里:Socket是什么
多線程Socket與單線程類似,只是使用了多線程的方式來管理連接,主線程負責接收連接,在接到連接后變創建新的線程,每個線程負責與自己的客戶端進行通信。
了解單線程Socket看這里:如何編寫單多線程Socket程序
與單線程Socket例子相比來說,服務端可以與多個客戶端進行通信了,不過多線程頻繁的創建與銷毀便會帶來很大的資源開銷,而系統的網絡資源等都是有限的。因此一般會引入線程池,可以在某種程度上重用線程,減少線程的創建和銷毀的次數以減少開銷。
我們的代碼也分為客戶端和服務端兩部分。服務端的代碼中包含了使用和不使用線程池的兩種方式。
服務端代碼:
?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:好好學習天天向上
posted on 2017-07-25 10:30 聽風 閱讀(124) 評論(0) 編輯 收藏 所屬分類: JAVA