如何編寫多線程Socket程序
1、如何編寫多線程Socket程序
了解Socket看這里:Socket是什么
多線程Socket與單線程類似,只是使用了多線程的方式來(lái)管理連接,主線程負(fù)責(zé)接收連接,在接到連接后變創(chuàng)建新的線程,每個(gè)線程負(fù)責(zé)與自己的客戶端進(jìn)行通信。
了解單線程Socket看這里:如何編寫單多線程Socket程序
與單線程Socket例子相比來(lái)說(shuō),服務(wù)端可以與多個(gè)客戶端進(jìn)行通信了,不過(guò)多線程頻繁的創(chuàng)建與銷毀便會(huì)帶來(lái)很大的資源開(kāi)銷,而系統(tǒng)的網(wǎng)絡(luò)資源等都是有限的。因此一般會(huì)引入線程池,可以在某種程度上重用線程,減少線程的創(chuàng)建和銷毀的次數(shù)以減少開(kāi)銷。
我們的代碼也分為客戶端和服務(wù)端兩部分。服務(wù)端的代碼中包含了使用和不使用線程池的兩種方式。
服務(wù)端代碼:
?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?時(shí)最多支持?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??????*?線程類,負(fù)責(zé)維持與一個(gè)客戶端的通信
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?
運(yùn)行服務(wù)端代碼后,程序會(huì)一直進(jìn)行監(jiān)聽(tīng),直到接收到客戶端請(qǐng)求為止。結(jié)果如下:
waitting connet…
客戶端代碼(與單線程完全相同):
?1?public?class?SocketDemoClient?{
?2?
?3?????private?String?host?=?"127.0.0.1";//?要發(fā)送給服務(wù)端的ip
?4?
?5?????private?int?port?=?8000;//?要發(fā)送給服務(wù)端的端口
?6?
?7?????private?Socket?socket;
?8?
?9?????public?SocketDemoClient()?throws?Exception?{
10?????????socket?=?new?Socket(host,?port);//?構(gòu)造Socket客戶端,并與連接服務(wù)端
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?????????????//?讀取本地控制臺(tái)的消息
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?}
由于我們要測(cè)試多個(gè)客戶端連接同一個(gè)服務(wù)端,所以我們需要多次運(yùn)行客戶端代碼。這里我們運(yùn)行兩次之后(稱為客戶端1、客戶端2),查看服務(wù)端的Console,會(huì)出現(xiàn)以下結(jié)果,說(shuō)明已經(jīng)連接成功:
waitting connet…
new connection accepted:/127.0.0.1:59593
new connection accepted:/127.0.0.1:59596
我們?cè)谌?font color="#ff0000">客戶端1的Console中輸入我們要發(fā)送的消息”維護(hù)世界和平”,回車確定后,客戶端1的Console出現(xiàn)以下結(jié)果,消息已經(jīng)發(fā)出:
send msg:維護(hù)世界和平
再去客戶端2的Console中輸入”好好學(xué)習(xí)天天向上”,回車確定后,客戶端2的Console出現(xiàn)以下結(jié)果,消息已經(jīng)發(fā)出:
send msg:好好學(xué)習(xí)天天向上
在服務(wù)端的Console中,我們會(huì)看到如下結(jié)果,說(shuō)明兩個(gè)客戶端的消息已經(jīng)被接受:
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:維護(hù)世界和平
from /127.0.0.1:59596, receive msg:好好學(xué)習(xí)天天向上
posted on 2017-07-25 10:30 聽(tīng)風(fēng) 閱讀(114) 評(píng)論(0) 編輯 收藏 所屬分類: JAVA