最近比較閑,一直在抽空回顧一些Java方面的技術應用。
今天沒什么事做,基于UDP協議,寫了一個非常簡單的聊天室程序。
現在的工作,很少用到socket,也算是對Java網絡編程方面的一個簡單回憶。
先看一下效果:
實現的效果可以說是非常非常簡單,但還是可以簡單的看到一個實現原理。
“聊天室001”的用戶,小紅和小綠相互聊了兩句,“聊天室002”的小黑無人理會,在一旁寂寞著。
看一下代碼實現:
1、首先是消息服務器的實現,功能很簡單:
•將客戶端的信息(進入了哪一個聊天室等)進行登記;
•構造UDP協議套接字對象,接受各個客戶端發送的消息;
•解析消息內容,將聊天信息推送回對應聊天室的各個客戶端;
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; //聊天服務器 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>>(); // 構造器 public ChatServer() { try { // 消息接受套接字對象的構造初始化 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>(); } // 將此次進入聊天室的用戶登記 clients.add(client); // 更新聊天室信息 groups.put(groupID, clients); } // 循環接收消息 @Override public void run() { while ( true ) { receiveMessage(); } } private void receiveMessage() { // UDP數據包 byte [] buf = new byte [ 1024 ]; DatagramPacket packet = new DatagramPacket(buf, buf.length); while ( true ) { try { // 接受數據包 server.receive(packet); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 解析數據包,獲取聊天信息 String content = new String(packet.getData(), 0 , packet.getLength()); // 通過第三方包解析json數據 Gson gson = new Gson(); MessageEntity me = gson.fromJson(content, MessageEntity. class ); // 解析消息內容,通過聊天室ID,獲取該聊天室的所有在線用戶 ArrayList<ChatClient> clients = groups.get(me.getGroupId()); // 將接收到的消息推送回該聊天室的各個用戶 for (ChatClient client : clients) { client.pushBackMessage(me); } } } } |
2、客戶端程序,依然很簡單:
•簡單的定義客戶端聊天室界面。
•構造消息發送套接字對象。
•獲取聊天信息框的內容,發送到服務器。
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; // 客戶端消息發送服務套接字 private DatagramSocket msg_send; // 服務端口 private final int PORT = 10000 ; // 服務器IP地址 private InetAddress ip; // 客戶端控件 TextField tf = new TextField( 20 ); TextArea ta = new TextArea(); Button send = new Button( "send" ); // 客戶端構造器 public ChatClient(String groupID, String clientName) { super ( "聊天室:" + groupID + "/" + clientName); this .clientName = clientName; this .groupID = groupID; // 設置客戶端界面樣式 add( "North" , tf); add( "Center" , ta); add( "South" , send); setSize( 250 , 250 ); show(); // 聊天相關服務器初始化 init(); // 監視器 addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent e) { // 關閉消息發送服務 msg_send.close(); // 關閉客戶端程序 dispose(); System.exit( 0 ); } }); } // 聊天相關服務器初始化 private void init() { // 注冊當前用戶及所在聊天室信息注冊到服務器 ChatServer.logInGroup(groupID, this ); try { // 初始化消息發送套接字對象 msg_send = new DatagramSocket(); // 指定消息服務器 try { ip = InetAddress.getByName( "127.0.0.1" ); } catch (UnknownHostException e) { System.out.println( "未知的主機異常.." ); } } catch (SocketException e) { System.out.println( "套接字連接異常.." ); } } // 消息發送按鈕時間監聽 public boolean action(Event evt, Object arg) { if (evt.target.equals(send)) { try { // 獲取輸入內容 String content = tf.getText(); // 發送消息 send_message(content); // 清空聊天框 tf.setText( null ); } catch (Exception ioe) { System.out.print(ioe.getMessage()); } } return true ; } // 消息發送 private void send_message(String content) { // 消息格式化(json格式) String message = messageFormat(content); // 將消息封裝成UDP數據包 byte [] buf = message.getBytes(); DatagramPacket packet = new DatagramPacket(buf, buf.length, ip, PORT); try { // 通過UDP協議發送消息 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(); } // 從服務器獲取當前聊天室最新消息(回調..) public void pushBackMessage(MessageEntity me) { ta.append(me.getUserName() + ":" + me.getText()); ta.append( "\n" ); } } |
3、消息實體類
主要就是用于將消息封裝成對象,包含:聊天室ID、消息發送者昵稱,消息內容。使用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; //消息實體 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,到了這里就基本搞定了,建立一個測試類。
•開啟消息服務器。
•開啟三個客戶端,其中兩個進入“聊天室001”,另一個進入“聊天室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" , "小黑" ); } } |
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。