java socket(套接字)通常也稱作"套接字",用于描述ip地址和端口,是一個通信鏈的句柄。應用程序通常通過"套接字"向網絡發出請求或者應答網絡請求。
使用socket實現多個客戶端和同一客戶端通訊;首先客戶端連接服務端發送一條消息,服務端接收到消息后進行處理,完成后再回復客戶端一條消息。本人通過自己的思維編寫了一份服務端和客戶端實現的代碼,望能與大家相互學習,共同進步。
服務端代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
/** * socket服務端 * 功能說明: * */ public class server { /** * 入口 * * @param args * @throws ioexception */ public static void main(string[] args) throws ioexception { // 為了簡單起見,所有的異常信息都往外拋 int port = 8899 ; // 定義一個servicesocket監聽在端口8899上 serversocket server = new serversocket(port); system.out.println( "等待與客戶端建立連接..." ); while ( true ) { // server嘗試接收其他socket的連接請求,server的accept方法是阻塞式的 socket socket = server.accept(); /** * 我們的服務端處理客戶端的連接請求是同步進行的, 每次接收到來自客戶端的連接請求后, * 都要先跟當前的客戶端通信完之后才能再處理下一個連接請求。 這在并發比較多的情況下會嚴重影響程序的性能, * 為此,我們可以把它改為如下這種異步處理與客戶端通信的方式 */ // 每接收到一個socket就建立一個新的線程來處理它 new thread( new task(socket)).start(); } // server.close(); } /** * 處理socket請求的線程類 */ static class task implements runnable { private socket socket; /** * 構造函數 */ public task(socket socket) { this .socket = socket; } @override public void run() { try { handlersocket(); } catch (exception e) { e.printstacktrace(); } } /** * 跟客戶端socket進行通信 * * @throws ioexception */ private void handlersocket() throws exception { // 跟客戶端建立好連接之后,我們就可以獲取socket的inputstream,并從中讀取客戶端發過來的信息了 /** * 在從socket的inputstream中接收數據時,像上面那樣一點點的讀就太復雜了, * 有時候我們就會換成使用bufferedreader來一次讀一行 * * bufferedreader的readline方法是一次讀一行的,這個方法是阻塞的,直到它讀到了一行數據為止程序才會繼續往下執行, * 那么readline什么時候才會讀到一行呢?直到程序遇到了換行符或者是對應流的結束符readline方法才會認為讀到了一行, * 才會結束其阻塞,讓程序繼續往下執行。 * 所以我們在使用bufferedreader的readline讀取數據的時候一定要記得在對應的輸出流里面一定要寫入換行符( * 流結束之后會自動標記為結束,readline可以識別),寫入換行符之后一定記得如果輸出流不是馬上關閉的情況下記得flush一下, * 這樣數據才會真正的從緩沖區里面寫入。 */ bufferedreader br = new bufferedreader( new inputstreamreader(socket.getinputstream(), "utf-8" )); stringbuilder sb = new stringbuilder(); string temp; int index; while ((temp = br.readline()) != null ) { if ((index = temp.indexof( "eof" )) != - 1 ) { // 遇到eof時就結束接收 sb.append(temp.substring( 0 , index)); break ; } sb.append(temp); } system.out.println( "form cliect[port:" + socket.getport() + "] 消息內容:" + sb.tostring()); // 回應一下客戶端 writer writer = new outputstreamwriter(socket.getoutputstream(), "utf-8" ); writer.write(string.format( "hi,%d.天朗氣清,惠風和暢!" , socket.getport())); writer.flush(); writer.close(); system.out.println( "to cliect[port:" + socket.getport() + "] 回復客戶端的消息發送成功" ); br.close(); socket.close(); } } } |
客戶端代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
import java.io.inputstreamreader; import java.io.outputstreamwriter; import java.io.reader; import java.io.writer; import java.net.socket; /** * socket客戶端 * 功能說明: * * @author 大智若愚的小懂 * @date 2016年8月30日 * @version 1.0 */ public class client { /** * 入口 * @param args */ public static void main(string[] args) { // 開啟三個客戶端,一個線程代表一個客戶端 for ( int i = 0 ; i < 3 ; i++) { new thread( new runnable() { @override public void run() { try { testclient client = testclientfactory.createclient(); client.send(string.format( "hello,server!i'm %d.這周末天氣如何。" , client.client.getlocalport())); client.receive(); } catch (exception e) { e.printstacktrace(); } } } ).start(); } } /** * 生產測試客戶端的工廠 */ static class testclientfactory { public static testclient createclient() throws exception { return new testclient( "127.0.0.1" , 8899 ); } } /** * 測試客戶端 */ static class testclient { /** * 構造函數 * @param host 要連接的服務端ip地址 * @param port 要連接的服務端對應的監聽端口 * @throws exception */ public testclient(string host, int port) throws exception { // 與服務端建立連接 this .client = new socket(host, port); system.out.println( "cliect[port:" + client.getlocalport() + "] 與服務端建立連接..." ); } private socket client; private writer writer; /** * 發送消息 * @param msg * @throws exception */ public void send(string msg) throws exception { // 建立連接后就可以往服務端寫數據了 if (writer == null ) { writer = new outputstreamwriter(client.getoutputstream(), "utf-8" ); } writer.write(msg); writer.write( "eof\n" ); writer.flush(); // 寫完后要記得flush system.out.println( "cliect[port:" + client.getlocalport() + "] 消息發送成功" ); } /** * 接收消息 * @throws exception */ public void receive() throws exception { // 寫完以后進行讀操作 reader reader = new inputstreamreader(client.getinputstream(), "utf-8" ); // 設置接收數據超時間為10秒 client.setsotimeout( 10 * 1000 ); char [] chars = new char [ 64 ]; int len; stringbuilder sb = new stringbuilder(); while ((len = reader.read(chars)) != - 1 ) { sb.append( new string(chars, 0 , len)); } system.out.println( "cliect[port:" + client.getlocalport() + "] 消息收到了,內容:" + sb.tostring()); reader.close(); // 關閉連接 writer.close(); client.close(); } } } |
接下來模擬一下:
1.首先運行服務端
2.接著運行客戶端(開三個客戶端請求)
為了演示有所區分,服務端我使用的是eclipse工具,客戶端使用的是intellij idea工具。這時可以看到客戶端在控制臺打印出來的消息
一個port端口號代表一個客戶端,回過來看下服務端在控制臺打印出來的消息
總結
以上就是本文關于java編程socket實現多個客戶端連接同一個服務端代碼的全部內容,希望對大家有所幫助。有問題可以留言,小編會及時回復大家的。
原文鏈接:https://www.2cto.com/kf/201609/543865.html