Server

  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() + "
");
 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                             + "
");
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("服务器成功停止!
");
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() + "上线!
");
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() + "下线!
");
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 + "
");
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