最近比较闲,一直在抽空回顾一些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" , "小黑" ); } } |
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。