1 package com.arvin.chat;
2
3 import java.awt.BorderLayout;
4 import java.awt.Color;
5 import java.awt.GridLayout;
6 import java.awt.Toolkit;
7 import java.awt.event.ActionEvent;
8 import java.awt.event.ActionListener;
9 import java.awt.event.WindowAdapter;
10 import java.awt.event.WindowEvent;
11 import java.io.BufferedReader;
12 import java.io.IOException;
13 import java.io.InputStreamReader;
14 import java.io.PrintWriter;
15 import java.net.BindException;
16 import java.net.ServerSocket;
17 import java.net.Socket;
18 import java.util.ArrayList;
19 import java.util.StringTokenizer;
20
21 import javax.swing.DefaultListModel;
22 import javax.swing.JButton;
23 import javax.swing.JFrame;
24 import javax.swing.JLabel;
25 import javax.swing.JList;
26 import javax.swing.JOptionPane;
27 import javax.swing.JPanel;
28 import javax.swing.JScrollPane;
29 import javax.swing.JSplitPane;
30 import javax.swing.JTextArea;
31 import javax.swing.JTextField;
32 import javax.swing.border.TitledBorder;
33
34 public class Server {
35
36 private JFrame frame;
37 private JTextArea contentArea;
38 private JTextField txt_message;
39 private JTextField txt_max;
40 private JTextField txt_port;
41 private JButton btn_start;
42 private JButton btn_stop;
43 private JButton btn_send;
44 private JPanel northPanel;
45 private JPanel southPanel;
46 private JScrollPane rightPanel;
47 private JScrollPane leftPanel;
48 private JSplitPane centerSplit;
49 private JList userList;
50 private DefaultListModel listModel;
51
52 private ServerSocket serverSocket;
53 private ServerThread serverThread;
54 private ArrayList<ClientThread>
clients;
55
56 private boolean isStart =
false;
57
58 // 主方法,程序执行入口
59 public static void main(String[] args) {
60 new Server();
61 }
62
63 // 执行消息发送
64 public void send() {
65 if (!
isStart) {
66 JOptionPane.showMessageDialog(frame, "服务器还未启动,不能发送消息!", "错误"
,
67 JOptionPane.ERROR_MESSAGE);
68 return;
69 }
70 if (clients.size() == 0
) {
71 JOptionPane.showMessageDialog(frame, "没有用户在线,不能发送消息!", "错误"
,
72 JOptionPane.ERROR_MESSAGE);
73 return;
74 }
75 String message =
txt_message.getText().trim();
76 if (message ==
null || message.equals(""
)) {
77 JOptionPane.showMessageDialog(frame, "消息不能为空!", "错误"
,
78 JOptionPane.ERROR_MESSAGE);
79 return;
80 }
81 sendServerMessage(message);
// 群发服务器消息
82 contentArea.append("服务器说:" + txt_message.getText() + "\r\n"
);
83 txt_message.setText(
null);
84 }
85
86 // 构造放法
87 public Server() {
88 frame =
new JFrame("服务器"
);
89 // 更改JFrame的图标:
90 //frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Client.class.getResource("qq.png")));
91 //frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Server.class.getResource("qq.png")));
92 contentArea =
new JTextArea();
93 contentArea.setEditable(
false);
94 contentArea.setForeground(Color.blue);
95 txt_message =
new JTextField();
96 txt_max =
new JTextField("30"
);
97 txt_port =
new JTextField("8888"
);
98 btn_start =
new JButton("启动"
);
99 btn_stop =
new JButton("停止"
);
100 btn_send =
new JButton("发送"
);
101 btn_stop.setEnabled(
false);
102 listModel =
new DefaultListModel();
103 userList =
new JList(listModel);
104
105 southPanel =
new JPanel(
new BorderLayout());
106 southPanel.setBorder(
new TitledBorder("写消息"
));
107 southPanel.add(txt_message, "Center"
);
108 southPanel.add(btn_send, "East"
);
109 leftPanel =
new JScrollPane(userList);
110 leftPanel.setBorder(
new TitledBorder("在线用户"
));
111
112 rightPanel =
new JScrollPane(contentArea);
113 rightPanel.setBorder(
new TitledBorder("消息显示区"
));
114
115 centerSplit =
new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel,
116 rightPanel);
117 centerSplit.setDividerLocation(100
);
118 northPanel =
new JPanel();
119 northPanel.setLayout(
new GridLayout(1, 6
));
120 northPanel.add(
new JLabel("人数上限"
));
121 northPanel.add(txt_max);
122 northPanel.add(
new JLabel("端口"
));
123 northPanel.add(txt_port);
124 northPanel.add(btn_start);
125 northPanel.add(btn_stop);
126 northPanel.setBorder(
new TitledBorder("配置信息"
));
127
128 frame.setLayout(
new BorderLayout());
129 frame.add(northPanel, "North"
);
130 frame.add(centerSplit, "Center"
);
131 frame.add(southPanel, "South"
);
132 frame.setSize(650, 400
);
133 //frame.setSize(Toolkit.getDefaultToolkit().getScreenSize());//设置全屏
134 int screen_width =
Toolkit.getDefaultToolkit().getScreenSize().width;
135 int screen_height =
Toolkit.getDefaultToolkit().getScreenSize().height;
136 frame.setLocation((screen_width - frame.getWidth()) / 2
,
137 (screen_height - frame.getHeight()) / 2
);
138 frame.setVisible(
true);
139
140 // 关闭窗口时事件
141 frame.addWindowListener(
new WindowAdapter() {
142 public void windowClosing(WindowEvent e) {
143 if (isStart) {
144 closeServer();
// 关闭服务器
145 }
146 System.exit(0);
// 退出程序
147 }
148 });
149
150 // 文本框按回车键时事件
151 txt_message.addActionListener(
new ActionListener() {
152 public void actionPerformed(ActionEvent e) {
153 send();
154 }
155 });
156
157 // 单击发送按钮时事件
158 btn_send.addActionListener(
new ActionListener() {
159 public void actionPerformed(ActionEvent arg0) {
160 send();
161 }
162 });
163
164 // 单击启动服务器按钮时事件
165 btn_start.addActionListener(
new ActionListener() {
166 public void actionPerformed(ActionEvent e) {
167 if (isStart) {
168 JOptionPane.showMessageDialog(frame, "服务器已处于启动状态,不要重复启动!"
,
169 "错误"
, JOptionPane.ERROR_MESSAGE);
170 return;
171 }
172 int max;
173 int port;
174 try {
175 try {
176 max =
Integer.parseInt(txt_max.getText());
177 }
catch (Exception e1) {
178 throw new Exception("人数上限为正整数!"
);
179 }
180 if (max <= 0
) {
181 throw new Exception("人数上限为正整数!"
);
182 }
183 try {
184 port =
Integer.parseInt(txt_port.getText());
185 }
catch (Exception e1) {
186 throw new Exception("端口号为正整数!"
);
187 }
188 if (port <= 0
) {
189 throw new Exception("端口号为正整数!"
);
190 }
191 serverStart(max, port);
192 contentArea.append("服务器已成功启动!人数上限:" + max + ",端口:" +
port
193 + "\r\n"
);
194 JOptionPane.showMessageDialog(frame, "服务器成功启动!"
);
195 btn_start.setEnabled(
false);
196 txt_max.setEnabled(
false);
197 txt_port.setEnabled(
false);
198 btn_stop.setEnabled(
true);
199 }
catch (Exception exc) {
200 JOptionPane.showMessageDialog(frame, exc.getMessage(),
201 "错误"
, JOptionPane.ERROR_MESSAGE);
202 }
203 }
204 });
205
206 // 单击停止服务器按钮时事件
207 btn_stop.addActionListener(
new ActionListener() {
208 public void actionPerformed(ActionEvent e) {
209 if (!
isStart) {
210 JOptionPane.showMessageDialog(frame, "服务器还未启动,无需停止!", "错误"
,
211 JOptionPane.ERROR_MESSAGE);
212 return;
213 }
214 try {
215 closeServer();
216 btn_start.setEnabled(
true);
217 txt_max.setEnabled(
true);
218 txt_port.setEnabled(
true);
219 btn_stop.setEnabled(
false);
220 contentArea.append("服务器成功停止!\r\n"
);
221 JOptionPane.showMessageDialog(frame, "服务器成功停止!"
);
222 }
catch (Exception exc) {
223 JOptionPane.showMessageDialog(frame, "停止服务器发生异常!", "错误"
,
224 JOptionPane.ERROR_MESSAGE);
225 }
226 }
227 });
228 }
229
230 // 启动服务器
231 public void serverStart(
int max,
int port)
throws java.net.BindException {
232 try {
233 clients =
new ArrayList<ClientThread>
();
234 serverSocket =
new ServerSocket(port);
235 serverThread =
new ServerThread(serverSocket, max);
236 serverThread.start();
237 isStart =
true;
238 }
catch (BindException e) {
239 isStart =
false;
240 throw new BindException("端口号已被占用,请换一个!"
);
241 }
catch (Exception e1) {
242 e1.printStackTrace();
243 isStart =
false;
244 throw new BindException("启动服务器异常!"
);
245 }
246 }
247
248 // 关闭服务器
249 @SuppressWarnings("deprecation"
)
250 public void closeServer() {
251 try {
252 if (serverThread !=
null)
253 serverThread.stop();
// 停止服务器线程
254
255 for (
int i = clients.size() - 1; i >= 0; i--
) {
256 // 给所有在线用户发送关闭命令
257 clients.get(i).getWriter().println("CLOSE"
);
258 clients.get(i).getWriter().flush();
259 // 释放资源
260 clients.get(i).stop();
// 停止此条为客户端服务的线程
261 clients.get(i).reader.close();
262 clients.get(i).writer.close();
263 clients.get(i).socket.close();
264 clients.remove(i);
265 }
266 if (serverSocket !=
null) {
267 serverSocket.close();
// 关闭服务器端连接
268 }
269 listModel.removeAllElements();
// 清空用户列表
270 isStart =
false;
271 }
catch (IOException e) {
272 e.printStackTrace();
273 isStart =
true;
274 }
275 }
276
277 // 群发服务器消息
278 public void sendServerMessage(String message) {
279 for (
int i = clients.size() - 1; i >= 0; i--
) {
280 clients.get(i).getWriter().println("服务器:" + message + "(多人发送)"
);
281 clients.get(i).getWriter().flush();
282 }
283 }
284
285 // 服务器线程
286 class ServerThread
extends Thread {
287 private ServerSocket serverSocket;
288 private int max;
// 人数上限
289
290
291 // 服务器线程的构造方法
292 public ServerThread(ServerSocket serverSocket,
int max) {
293 this.serverSocket =
serverSocket;
294 this.max =
max;
295 }
296
297 public void run() {
298 while (
true) {
// 不停的等待客户端的链接
299 try {
300 Socket socket =
serverSocket.accept();
301
302 if (clients.size() == max) {
// 如果已达人数上限
303 BufferedReader r =
new BufferedReader(
304 new InputStreamReader(socket.getInputStream()));
305 PrintWriter w =
new PrintWriter(socket
306 .getOutputStream());
307 // 接收客户端的基本用户信息
308 String inf =
r.readLine();
309 StringTokenizer st =
new StringTokenizer(inf, "@"
);
310 User user =
new User(st.nextToken(), st.nextToken());
311 // 反馈连接成功信息
312 w.println("MAX@服务器:对不起," +
user.getName()
313 + user.getIp() + ",服务器在线人数已达上限,请稍后尝试连接!"
);
314 w.flush();
315 // 释放资源
316 r.close();
317 w.close();
318 socket.close();
319 continue;
320 }
321
322
323 ClientThread client =
new ClientThread(socket);
324 client.start();
// 开启对此客户端服务的线程
325 clients.add(client);
326 listModel.addElement(client.getUser().getName());
// 更新在线列表
327 contentArea.append(client.getUser().getName()
328 + client.getUser().getIp() + "上线!\r\n"
);
329 }
catch (IOException e) {
330 e.printStackTrace();
331 }
332 }
333 }
334 }
335
336 // 为一个客户端服务的线程
337 class ClientThread
extends Thread {
338 private Socket socket;
339 private BufferedReader reader;
340 private PrintWriter writer;
341 private User user;
342 private boolean isPassword =
false;
//验证密码
343
344 public BufferedReader getReader() {
345 return reader;
346 }
347
348 public PrintWriter getWriter() {
349 return writer;
350 }
351
352 public User getUser() {
353 return user;
354 }
355
356 // 客户端线程的构造方法
357 public ClientThread(Socket socket) {
358 try {
359 this.socket =
socket;
360 reader =
new BufferedReader(
new InputStreamReader(socket
361 .getInputStream()));
362 writer =
new PrintWriter(socket.getOutputStream());
363 // 接收客户端的基本用户信息
364 String inf =
reader.readLine();
365 StringTokenizer st =
new StringTokenizer(inf, "@"
);
366 user =
new User(st.nextToken(), st.nextToken(), st.nextToken());
367
368 // if(!isPassword){
369 // // 反馈密码错误信息
370 // writer.println("WrongPassword"+"@"+user.getName() + user.getIp() + "密码错误,与服务器连接失败!");
371 // writer.flush();
372 // return;
373 // }
374 //
375
376 System.out.println(user.getName()+" "+user.getIp()+" "+
user.getPassword());
377 // 反馈连接成功信息
378 writer.println(user.getName() + user.getIp() + "与服务器连接成功!"
);
379 writer.flush();
380 // 反馈当前在线用户信息
381 if (clients.size() > 0
) {
382 String temp = ""
;
383 for (
int i = clients.size() - 1; i >= 0; i--
) {
384 temp += (clients.get(i).getUser().getName() + "/" + clients.get(i).getUser().getIp())+ "@"
;
385 }
386 writer.println("USERLIST@" + clients.size() + "@" +
temp);
387 writer.flush();
388 }
389 // 向所有在线用户发送该用户上线命令
390 for (
int i = clients.size() - 1; i >= 0; i--
) {
391 clients.get(i).getWriter().println(
392 "ADD@" + user.getName() +
user.getIp());
393 clients.get(i).getWriter().flush();
394 }
395 }
catch (IOException e) {
396 e.printStackTrace();
397 }
398 }
399
400 @SuppressWarnings("deprecation"
)
401 public void run() {
// 不断接收客户端的消息,进行处理。
402 String message =
null;
403 while (
true) {
404 try {
405 message = reader.readLine();
// 接收客户端消息
406 if (message.equals("CLOSE"))
// 下线命令
407 {
408 contentArea.append(
this.getUser().getName()
409 +
this.getUser().getIp() + "下线!\r\n"
);
410 // 断开连接释放资源
411 reader.close();
412 writer.close();
413 socket.close();
414
415 // 向所有在线用户发送该用户的下线命令
416 for (
int i = clients.size() - 1; i >= 0; i--
) {
417 clients.get(i).getWriter().println("DELETE@" +
user.getName());
418 clients.get(i).getWriter().flush();
419 }
420
421 listModel.removeElement(user.getName());
// 更新在线列表
422
423 // 删除此条客户端服务线程
424 for (
int i = clients.size() - 1; i >= 0; i--
) {
425 if (clients.get(i).getUser() ==
user) {
426 ClientThread temp =
clients.get(i);
427 clients.remove(i);
// 删除此用户的服务线程
428 temp.stop();
// 停止这条服务线程
429 return;
430 }
431 }
432 }
else {
433 dispatcherMessage(message);
// 转发消息
434 }
435 }
catch (IOException e) {
436 e.printStackTrace();
437 }
438 }
439 }
440
441 // 转发消息
442 public void dispatcherMessage(String message) {
443 StringTokenizer stringTokenizer =
new StringTokenizer(message, "@"
);
444 String source =
stringTokenizer.nextToken();
445 String owner =
stringTokenizer.nextToken();
446 String content =
stringTokenizer.nextToken();
447 message = source + "说:" +
content;
448 contentArea.append(message + "\r\n"
);
449 if (owner.equals("ALL")) {
// 群发
450 for (
int i = clients.size() - 1; i >= 0; i--
) {
451 clients.get(i).getWriter().println(message + "(多人发送)"
);
452 clients.get(i).getWriter().flush();
453 }
454 }
455 }
456 }
457 }
转载于:https://www.cnblogs.com/Arvin-9/p/5075329.html