在上一篇,利用线程使服务端实现了能够接收多客户端请求的功能,这里便需要客户端接收多客户端消息的同时还能把消息转发到每个连接的客户端,并且客户端要能在内容显示区域显示出来,从而实现简单的在线群聊。
在实现客户端转发,无非就是增加输出流;而之前客户端都只发不收,这里也需要更改客户端达到循环接收服务端消息的目的,因此也需要实现多线程。
在实现这个功能的时候,偶然想起随机生成验证码的功能,于是也灵机一动随机给每个客户端生成一个名字,从而在输出的时候看起来更加像是群聊,不仅有消息输出,还能看到是谁。
实现这些功能之后,基本上就可以几个人同时在线群聊了,因为代码中有main方法,因此可以把服务端和客户端都打成可执行jar包,
之后在桌面双击相应的jar文件启动服务端和客户端即可,不需要再依赖eclipse运行。
修改后的客户端代码如下:
[java] view plain copy
1. package
2.
3. import
4. import
5. import
6. import
7. import
8. import
9. import
10. import
11. import
12. import
13. import
14. import
15. import
16. import
17.
18. /**
19. * 在线聊天客户端 步骤: 1、生成图形窗口界面轮廓 2、为轮廓添加关闭事件 3、在轮廓中加入输入区域和内容展示区域 4、为输入区域添加回车事件
20. * 5、建立服务端连接并发送数据
21. *
22. * @author tuzongxun123
23. *
24. */
25. public class ChatClient extends
26. /**
27. *
28. */
29. private static final long
30. // 用户输入区域
31. private TextField tfTxt = new
32. // 内容展示区域
33. private TextArea tarea = new
34. private Socket socket = null;
35. // 数据输出流
36. private DataOutputStream dataOutputStream = null;
37. // 数据输入流
38. private DataInputStream dataInputStream = null;
39. private boolean isConnect = false;
40. new Thread(new
41. "";
42.
43. public static void
44. new
45. chatClient.createName();
46. chatClient.launcFrame();
47.
48. }
49.
50. /**
51. * 建立一个简单的图形化窗口
52. *
53. * @author:tuzongxun
54. * @Title: launcFrame
55. * @param
56. * @return void
57. * @date May 18, 2016 9:57:00 AM
58. * @throws
59. */
60. public void
61. 300, 200);
62. this.setSize(200, 400);
63. add(tfTxt, BorderLayout.SOUTH);
64. add(tarea, BorderLayout.NORTH);
65. // 根据窗口里面的布局及组件的preferedSize来确定frame的最佳大小
66. pack();
67. // 监听图形界面窗口的关闭事件
68. this.addWindowListener(new
69.
70. @Override
71. public void
72. 0);
73. disConnect();
74. }
75. });
76. new
77. // 设置窗口可见
78. true);
79. connect();
80. // 启动接受消息的线程
81. tReceive.start();
82. }
83.
84. /**
85. * 连接服务器
86. *
87. * @author:tuzongxun
88. * @Title: connect
89. * @param
90. * @return void
91. * @date May 18, 2016 9:56:49 AM
92. * @throws
93. */
94. public void
95. try
96. // 新建服务端连接
97. new Socket("127.0.0.1", 8888);
98. // 获取客户端输出流
99. new
100. new
101. "连上服务端");
102. true;
103. catch
104. e.printStackTrace();
105. catch
106. e.printStackTrace();
107. }
108. }
109.
110. // 生成随机的客户端名字
111. public void
112. "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
113. "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
114. "w", "x", "y", "z", "1", "2", "3", "4", "5", "6", "7", "8",
115. "9", "0", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
116. "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
117. "W", "X", "Y", "Z"
118. new
119.
120. for (int i = 0; i < 6; i++) {
121. // long num = Math.round(Math.random() * (str1.length - 0) + 0);
122. // int n = (int) num;
123. int
124. if
125. String str = str1[n];
126. name = name + str;
127. System.out.println(name);
128. else
129. i--;
130. continue;
131. }
132.
133. }
134. this.setTitle(name);
135. }
136.
137. /**
138. * 关闭客户端资源
139. *
140. * @author:tuzongxun
141. * @Title: disConnect
142. * @param
143. * @return void
144. * @date May 18, 2016 9:57:46 AM
145. * @throws
146. */
147. public void
148. try
149. false;
150. // 停止线程
151. tReceive.join();
152. catch
153. e.printStackTrace();
154. finally
155. try
156. if (dataOutputStream != null) {
157. dataOutputStream.close();
158. }
159. if (socket != null) {
160. socket.close();
161. null;
162. }
163.
164. catch
165. e.printStackTrace();
166. }
167. }
168. }
169.
170. /**
171. * 向服务端发送消息
172. *
173. * @author:tuzongxun
174. * @Title: sendMessage
175. * @param @param text
176. * @return void
177. * @date May 18, 2016 9:57:56 AM
178. * @throws
179. */
180. private void
181. try
182. ":"
183. dataOutputStream.flush();
184. catch
185. e1.printStackTrace();
186. }
187. }
188.
189. /**
190. * 图形窗口输入区域监听回车事件
191. *
192. * @author tuzongxun123
193. *
194. */
195. private class TFLister implements
196.
197. @Override
198. public void
199. String text = tfTxt.getText().trim();
200. // 清空输入区域信息
201. "");
202. // 回车后发送数据到服务器
203. sendMessage(text);
204. }
205.
206. }
207.
208. private class ReceiveThread implements
209.
210. @Override
211. public void
212. try
213. while
214. String message = dataInputStream.readUTF();
215. System.out.println(message);
216. String txt = tarea.getText();
217. if (txt != null && !"".equals(txt.trim())) {
218. "\n"
219. }
220. tarea.setText(message);
221. }
222. catch
223. e.printStackTrace();
224. }
225. }
226.
227. }
228. }
修改后的服务端代码如下:
[java] view plain copy
1. package
2.
3. import
4. import
5. import
6. import
7. import
8. import
9. import
10. import
11. import
12. import
13.
14. /**
15. * java使用socket和awt组件以及多线程简单实现在线聊天功能服务端 :
16. * 实现服务端把接收到的客户端信息转发到所有连接的客户端,并且让客户端读取到这些信息并显示在内容显示区域中。
17. *
18. * @author tuzongxun123
19. *
20. */
21. public class
22.
23. public static void
24. new
25. }
26.
27. // 是否成功启动服务端
28. private boolean isStart = false;
29. // 服务端socket
30. private ServerSocket ss = null;
31. // 客户端socket
32. private Socket socket = null;
33. // 保存客户端集合
34. new
35.
36. public void
37. try
38. // 启动服务器
39. new ServerSocket(8888);
40. catch
41. "端口已在使用中");
42. // 关闭程序
43. 0);
44. catch
45. e.printStackTrace();
46. }
47.
48. try
49. true;
50. while
51. // 启动监听
52. socket = ss.accept();
53. "one client connect");
54. // 启动客户端线程
55. new
56.
57. new
58. clients.add(client);
59. }
60. catch
61. e.printStackTrace();
62. finally
63. // 关闭服务
64. try
65. ss.close();
66. catch
67. e.printStackTrace();
68. }
69. }
70.
71. }
72.
73. /**
74. * 客户端线程
75. *
76. * @author tuzongxun123
77. *
78. */
79. private class Client implements
80. // 客户端socket
81. private Socket socket = null;
82. // 客户端输入流
83. private DataInputStream dataInputStream = null;
84. // 客户端输出流
85. private DataOutputStream dataOutputStream = null;
86. private boolean isConnect = false;
87.
88. public
89. this.socket = socket;
90. try
91. true;
92. // 获取客户端输入流
93. new
94. // 获取客户端输出流
95. new
96. socket.getOutputStream());
97. catch
98. e.printStackTrace();
99. }
100. }
101.
102. /**
103. * 向客户端群发(转发)数据
104. *
105. * @author:tuzongxun
106. * @Title: sendMessageToClients
107. * @param @param message
108. * @return void
109. * @date May 18, 2016 11:28:10 AM
110. * @throws
111. */
112. public void
113. try
114. dataOutputStream.writeUTF(message);
115. catch
116.
117. catch
118. e.printStackTrace();
119. }
120. }
121.
122. @Override
123. public void
124. true;
125. null;
126. try
127. while
128. // 读取客户端传递的数据
129. String message = dataInputStream.readUTF();
130. "客户端说:"
131. for (int i = 0; i < clients.size(); i++) {
132. c = clients.get(i);
133.
134. c.sendMessageToClients(message);
135. }
136.
137. }
138. catch
139. "client closed!");
140. catch
141. if (c != null) {
142. clients.remove(c);
143. }
144. "Client is Closed!!!!");
145. catch
146. e.printStackTrace();
147. finally
148. // 关闭相关资源
149. try
150. if (dataInputStream != null) {
151. dataInputStream.close();
152. }
153. if (socket != null) {
154. socket.close();
155. null;
156. }
157. catch
158. e.printStackTrace();
159. }
160. }
161. }
162. }
163.
164. }