最近比較閑,一直在抽空回顧一些Java方面的技術(shù)應(yīng)用。
今天沒什么事做,基于UDP協(xié)議,寫了一個(gè)非常簡單的聊天室程序。
現(xiàn)在的工作,很少用到socket,也算是對Java網(wǎng)絡(luò)編程方面的一個(gè)簡單回憶。
先看一下效果:
實(shí)現(xiàn)的效果可以說是非常非常簡單,但還是可以簡單的看到一個(gè)實(shí)現(xiàn)原理。
“聊天室001”的用戶,小紅和小綠相互聊了兩句,“聊天室002”的小黑無人理會(huì),在一旁寂寞著。
看一下代碼實(shí)現(xiàn):
1、首先是消息服務(wù)器的實(shí)現(xiàn),功能很簡單:
•將客戶端的信息(進(jìn)入了哪一個(gè)聊天室等)進(jìn)行登記;
•構(gòu)造UDP協(xié)議套接字對象,接受各個(gè)客戶端發(fā)送的消息;
•解析消息內(nèi)容,將聊天信息推送回對應(yīng)聊天室的各個(gè)客戶端;
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
|
package com.tsr.simplechat.receive_server; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException; import java.util.ArrayList; import java.util.HashMap; import com.google.gson.Gson; import com.tsr.simplechat.bean.MessageEntity; import com.tsr.simplechat.client.ChatClient; //聊天服務(wù)器 public class ChatServer extends Thread { // 程序占用端口號 private static final int PORT = 10000 ; // 消息接受套接字對象 private static DatagramSocket server = null ; // 字典對象(Key:聊天室ID,Value:該聊天室下的客戶端用戶集合); private static HashMap<String, ArrayList<ChatClient>> groups = new HashMap<String, ArrayList<ChatClient>>(); // 構(gòu)造器 public ChatServer() { try { // 消息接受套接字對象的構(gòu)造初始化 server = new DatagramSocket(PORT); } catch (SocketException e) { e.printStackTrace(); } } // 注冊聊天室新登錄用戶 public static void logInGroup(String groupID, ChatClient client) { // 通過聊天室ID,獲取該聊天室的所有在線用戶 ArrayList<ChatClient> clients = groups.get(groupID); if (clients == null ) { clients = new ArrayList<ChatClient>(); } // 將此次進(jìn)入聊天室的用戶登記 clients.add(client); // 更新聊天室信息 groups.put(groupID, clients); } // 循環(huán)接收消息 @Override public void run() { while ( true ) { receiveMessage(); } } private void receiveMessage() { // UDP數(shù)據(jù)包 byte [] buf = new byte [ 1024 ]; DatagramPacket packet = new DatagramPacket(buf, buf.length); while ( true ) { try { // 接受數(shù)據(jù)包 server.receive(packet); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 解析數(shù)據(jù)包,獲取聊天信息 String content = new String(packet.getData(), 0 , packet.getLength()); // 通過第三方包解析json數(shù)據(jù) Gson gson = new Gson(); MessageEntity me = gson.fromJson(content, MessageEntity. class ); // 解析消息內(nèi)容,通過聊天室ID,獲取該聊天室的所有在線用戶 ArrayList<ChatClient> clients = groups.get(me.getGroupId()); // 將接收到的消息推送回該聊天室的各個(gè)用戶 for (ChatClient client : clients) { client.pushBackMessage(me); } } } } |
2、客戶端程序,依然很簡單:
•簡單的定義客戶端聊天室界面。
•構(gòu)造消息發(fā)送套接字對象。
•獲取聊天信息框的內(nèi)容,發(fā)送到服務(wù)器。
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
package com.tsr.simplechat.client; import java.awt.Button; import java.awt.Event; import java.awt.Frame; import java.awt.TextArea; import java.awt.TextField; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; import com.tsr.simplechat.bean.MessageEntity; import com.tsr.simplechat.receive_server.ChatServer; //客戶端程序 public class ChatClient extends Frame { private static final long serialVersionUID = 1L; // 聊天室ID private String groupID; // 客戶端用戶名 private String clientName; // 客戶端消息發(fā)送服務(wù)套接字 private DatagramSocket msg_send; // 服務(wù)端口 private final int PORT = 10000 ; // 服務(wù)器IP地址 private InetAddress ip; // 客戶端控件 TextField tf = new TextField( 20 ); TextArea ta = new TextArea(); Button send = new Button( "send" ); // 客戶端構(gòu)造器 public ChatClient(String groupID, String clientName) { super ( "聊天室:" + groupID + "/" + clientName); this .clientName = clientName; this .groupID = groupID; // 設(shè)置客戶端界面樣式 add( "North" , tf); add( "Center" , ta); add( "South" , send); setSize( 250 , 250 ); show(); // 聊天相關(guān)服務(wù)器初始化 init(); // 監(jiān)視器 addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent e) { // 關(guān)閉消息發(fā)送服務(wù) msg_send.close(); // 關(guān)閉客戶端程序 dispose(); System.exit( 0 ); } }); } // 聊天相關(guān)服務(wù)器初始化 private void init() { // 注冊當(dāng)前用戶及所在聊天室信息注冊到服務(wù)器 ChatServer.logInGroup(groupID, this ); try { // 初始化消息發(fā)送套接字對象 msg_send = new DatagramSocket(); // 指定消息服務(wù)器 try { ip = InetAddress.getByName( "127.0.0.1" ); } catch (UnknownHostException e) { System.out.println( "未知的主機(jī)異常.." ); } } catch (SocketException e) { System.out.println( "套接字連接異常.." ); } } // 消息發(fā)送按鈕時(shí)間監(jiān)聽 public boolean action(Event evt, Object arg) { if (evt.target.equals(send)) { try { // 獲取輸入內(nèi)容 String content = tf.getText(); // 發(fā)送消息 send_message(content); // 清空聊天框 tf.setText( null ); } catch (Exception ioe) { System.out.print(ioe.getMessage()); } } return true ; } // 消息發(fā)送 private void send_message(String content) { // 消息格式化(json格式) String message = messageFormat(content); // 將消息封裝成UDP數(shù)據(jù)包 byte [] buf = message.getBytes(); DatagramPacket packet = new DatagramPacket(buf, buf.length, ip, PORT); try { // 通過UDP協(xié)議發(fā)送消息 msg_send.send(packet); } catch (IOException e) { System.out.println( "IO異常.." ); } } // 消息格式化 private String messageFormat(String content) { StringBuffer buffer = new StringBuffer(); buffer.append( "{\"groupId\":" ).append( "\"" ).append(groupID).append( "\"," ); buffer.append( "\"userName\":\"" ).append(clientName).append( "\"," ); buffer.append( "\"text\":\"" ).append(content).append( "\"}" ); return buffer.toString(); } // 從服務(wù)器獲取當(dāng)前聊天室最新消息(回調(diào)..) public void pushBackMessage(MessageEntity me) { ta.append(me.getUserName() + ":" + me.getText()); ta.append( "\n" ); } } |
3、消息實(shí)體類
主要就是用于將消息封裝成對象,包含:聊天室ID、消息發(fā)送者昵稱,消息內(nèi)容。使用json格式解析。
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
|
package com.tsr.simplechat.bean; //消息實(shí)體 public class MessageEntity { private String groupId; private String userName; private String text; public String getGroupId() { return groupId; } public void setGroupId(String groupId) { this .groupId = groupId; } public String getUserName() { return userName; } public void setUserName(String userName) { this .userName = userName; } public String getText() { return text; } public void setText(String text) { this .text = text; } } |
4、OK,到了這里就基本搞定了,建立一個(gè)測試類。
•開啟消息服務(wù)器。
•開啟三個(gè)客戶端,其中兩個(gè)進(jìn)入“聊天室001”,另一個(gè)進(jìn)入“聊天室002”。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import com.tsr.simplechat.client.ChatClient; import com.tsr.simplechat.receive_server.ChatServer; public class Test { public static void main(String[] args) { ChatServer r = new ChatServer(); r.start(); ChatClient c1 = new ChatClient( "001" , "小紅" ); ChatClient c2 = new ChatClient( "001" , "小綠" ); ChatClient c3 = new ChatClient( "002" , "小黑" ); } } |
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。