zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    计算器程序
    输入三个整数,输出最大数和最小数
    输入三个数a,b,c,要示按由小到大的顺序输出
    最短路
    luogu P3953 逛公园
    二分图匹配
    luogu P3231 消毒
    [bzoj2120] [洛谷P1903] 数颜色
    [bzoj2038] [洛谷P1494] [2009国家集训队] 小Z的袜子(hose)
    [洛谷P4012] [网络流24题] 深海机器人问题
  • 原文地址:https://www.cnblogs.com/Arvin-9/p/5075329.html
Copyright © 2011-2022 走看看