标签:
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 }
标签:
原文地址:http://www.cnblogs.com/Arvin-9/p/5075329.html