zoukankan      html  css  js  c++  java
  • 搞了个1.0版本,名字和预定的一样改成OIFaQ了

      服务器没启动的情况下直接启动客户端会报错,测试的时候无所谓,发布的时候一定要注意,下个版本修正。

      得给服务器写个GUI,测试的时候有命令行,发布之后就不对劲了,要关闭还得用任务管理器。

      客户端的独立线程在关闭框架的时候会报错,目前直接catch掉了,感觉不够优雅,之后修正。

      服务器端倒是好像没什么bug了。

      上边这句话说完我自己都不信。

      先把exe和jar发了。

      这小图标画得我自己都陶醉了。

      1 import java.io.*;
      2 import java.net.*;
      3 import java.util.ArrayList;
      4 
      5 /**
      6  * 服务器端。
      7  * 基本功能已经完成。
      8  * 实现了对每个客户端启动一个线程,阻塞式地从每个客户端接收消息,接收到之后向所有客户端发送。
      9  * 越级升到V1.0。
     10  * 
     11  * @author mlxy
     12  * @version 1.0
     13  * */
     14 public class SimChatServer {
     15     ServerSocket ss = null;
     16     ArrayList<Client> clients = null;
     17     
     18     /** 服务器构造方法,只用来初始化已连接客户端数。*/
     19     public SimChatServer() {clients = new ArrayList<Client>();}
     20     
     21     /** 主方法。*/
     22     public static void main(String[] args) {
     23         SimChatServer server = new SimChatServer();
     24         server.startUp();
     25     }
     26     
     27     /** 启动服务器。*/
     28     public void startUp() {
     29         // 尝试启动服务器,端口被占用则提示并退出。
     30         try {
     31             ss = new ServerSocket(2333);
     32         } catch (BindException e) {
     33             System.out.println("Port occupied.");
     34             System.exit(0);
     35         } catch (IOException ex) {
     36             ex.printStackTrace();
     37         }
     38 
     39         // 死循环,等待客户端连接,连接成功则启动一个新线程。
     40         try {
     41             while (true) {
     42                 Client newClient = new Client(ss.accept());
     43                 newClient.start();
     44                 clients.add(newClient);
     45                 System.out.println("Current clients: " + clients.size());
     46             }
     47         } catch (IOException e) {
     48             e.printStackTrace();
     49         }
     50     }
     51     
     52     /**
     53      * 内部类。
     54      * 单个客户端线程,包含了处理客户端发来信息的功能,以及向客户端发送信息的方法。
     55      * 
     56      * @author mlxy
     57      * @version 1.0
     58      */
     59     private class Client extends Thread {
     60         Socket singleSocket;
     61         ObjectInputStream singleInput;
     62         ObjectOutputStream singleOutput;
     63         
     64         /** 一个客户端线程的构造方法。*/
     65         public Client(Socket singleSocket) {
     66             this.singleSocket = singleSocket;
     67             System.out.println("Client connected.");
     68             try {
     69                 singleInput = new ObjectInputStream(singleSocket.getInputStream());
     70                 singleOutput = new ObjectOutputStream(singleSocket.getOutputStream());
     71             } catch (IOException e) {
     72                 e.printStackTrace();
     73             }
     74         }
     75 
     76         @Override
     77         public void run() {
     78             // 主运行部分,抓到客户端退出的异常就打印提示并退出。
     79             try {
     80                 // 死循环,读包拆包打印。
     81                 while (true) {
     82                     String[] packReceived = (String[]) singleInput.readObject();
     83                     System.out.println("[" + packReceived[0] + "]: " + packReceived[1]);
     84                     for (int i = 0; i < clients.size(); i++) {
     85                         clients.get(i).sendPackage(packReceived);
     86                     }
     87                 }
     88                 
     89             } catch (ClassNotFoundException e) {
     90                 e.printStackTrace();
     91             } catch (EOFException ex) {
     92                 System.out.println("Client disconnected.");
     93             } catch (IOException exc) {
     94                 exc.printStackTrace();
     95             } finally {
     96                 // 进程准备结束,释放相关资源。
     97                 try {
     98                     if (singleSocket != null)
     99                         singleSocket.close();
    100                     if (singleInput != null)
    101                         singleInput.close();
    102                     if (singleOutput != null)
    103                         singleOutput.close();
    104                     
    105                     // 报告当前客户端退出。
    106                     clientOut();
    107                 } catch (IOException e) {
    108                     e.printStackTrace();
    109                 }
    110             }
    111         }
    112         
    113         /** 向客户端发包的方法。*/
    114         public void sendPackage(Object o) {
    115             try {
    116                 singleOutput.writeObject(o);
    117                 singleOutput.flush();
    118             } catch (IOException e) {
    119                 e.printStackTrace();
    120             }
    121         }
    122         
    123         /** 管理客户端退出的方法。*/
    124         private void clientOut() {
    125             // 找出当前客户端所在下标并标记删除。不能一边遍历一边修改列表哇,同志。
    126             int indexToRemove = -1;
    127             for (int i = 0; i < clients.size(); i++) {
    128                 if (clients.get(i).equals(this)) {
    129                     indexToRemove = i;
    130                     break;
    131                 }
    132             }
    133             clients.remove(indexToRemove);
    134             System.out.println("Current clients: " + clients.size());
    135         }
    136     }
    137 }
    Server端
      1 import java.awt.*;
      2 import java.awt.event.*;
      3 
      4 import javax.swing.*;
      5 
      6 import java.io.*;
      7 import java.net.*;
      8 
      9 /**
     10  * 客户端程序。
     11  * 基本上实现了向服务器发包与从服务器收包的功能,已经达成基本需要,更新到V1.0。
     12  * ServerWaiter类还不完善,具体请参考注释。
     13  * 
     14  * @author mlxy
     15  * @version 1.0
     16  * */
     17 public class SimChatClient extends JFrame {
     18     private static final long serialVersionUID = 1685352502599359548L;
     19     
     20     // 框架相关变量。
     21     private JPanel panel;
     22     private JTextArea area;
     23     private JTextField field;
     24     
     25     // 用户相关变量。
     26     private String userID;
     27     private StringBuffer chatRecord = new StringBuffer("");
     28 
     29     // 网络相关变量。
     30     //private String serverIP; *备用*
     31     //private int serverPort; *备用*
     32     private Socket socket = null;
     33     private ObjectOutputStream oos = null;
     34     private ObjectInputStream ois = null;
     35 
     36     /** 默认构造方法,初始化用户ID及框架内容。 */
     37     public SimChatClient() {
     38         String userName = (String) JOptionPane.showInputDialog(
     39                 null, "请输入用户ID:", "新用户", JOptionPane.PLAIN_MESSAGE,
     40                 null, null, new String("Default"));
     41         if (userName == null)
     42             System.exit(0);
     43         else
     44             userID = userName;
     45 
     46         panel = new JPanel();
     47         panel.setLayout(new BorderLayout());
     48 
     49         area = new JTextArea();
     50         area.setLineWrap(true);
     51         area.setWrapStyleWord(true);
     52         area.setEditable(false);
     53         area.setBackground(new Color(255, 204, 255));
     54         JScrollPane scrollPane = new JScrollPane(area);
     55 
     56         field = new JTextField();
     57         field.setBackground(new Color(66, 204, 255));
     58         field.addActionListener(new FieldListener());
     59 
     60         panel.add(scrollPane, BorderLayout.CENTER);
     61         panel.add(field, BorderLayout.SOUTH);
     62 
     63         this.add(panel);
     64         this.addWindowListener(new WindowAdapter() {
     65 
     66             @Override
     67             public void windowClosing(WindowEvent e) {
     68                 disconnect();
     69                 System.exit(0);
     70             }
     71 
     72             @Override
     73             public void windowActivated(WindowEvent e) {
     74                 super.windowActivated(e);
     75                 field.requestFocusInWindow();
     76             }
     77         });
     78     }
     79 
     80     /** 主运行方法。 */
     81     public static void main(String[] args) {
     82         try {
     83             UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
     84         } catch (UnsupportedLookAndFeelException e) {
     85             e.printStackTrace();
     86         } catch (ClassNotFoundException e) {
     87             e.printStackTrace();
     88         } catch (InstantiationException e) {
     89             e.printStackTrace();
     90         } catch (IllegalAccessException e) {
     91             e.printStackTrace();
     92         }
     93         SimChatClient frame = new SimChatClient();
     94         frame.launchFrame();
     95         new Thread(frame.new ServerWaiter()).start();
     96     }
     97 
     98     /** 框架参数初始化。 */
     99     public void launchFrame() {
    100         setTitle("Simple Chat Online: " + userID);
    101         setSize(400, 500);
    102         setLocationRelativeTo(null);
    103         setVisible(true);
    104 
    105         connect();
    106     }
    107 
    108     /** 连接到服务器端。 */
    109     private void connect() {
    110         try {
    111             socket = new Socket("192.168.1.104", 2333);
    112             oos = new ObjectOutputStream(socket.getOutputStream());
    113         } catch (IOException e) {
    114             e.printStackTrace();
    115         }
    116         area.setText("Connection established.");
    117     }
    118 
    119     /** 释放资源,与服务器断开连接。 */
    120     private void disconnect() {
    121         try {
    122             ois.close();
    123             oos.close();
    124             System.exit(0);
    125         } catch (IOException e) {
    126             e.printStackTrace();
    127         }
    128     }
    129     
    130     /** 
    131      * 按照格式更新文本框内容。
    132      * 
    133      * @param userName 用户名
    134      * @param content 消息内容
    135      */
    136     private void updateTextArea(String userName, String content) {
    137         // 之后加上发送时间。
    138         chatRecord.append("[ " + userName + " ] : " + content + "
    ");
    139         area.setText(chatRecord.toString());
    140     }
    141 
    142     /** 内部类,输入框的监听器。 */
    143     private class FieldListener implements ActionListener {
    144 
    145         @Override
    146         public void actionPerformed(ActionEvent e) {
    147             // 按下回车后向服务器发包,然后清空输入框。
    148             sendPackage();
    149             field.setText("");
    150         }
    151 
    152         /** 私有方法,读取用户ID和输入内容,向服务器发送包。 */
    153         private void sendPackage() {
    154             String[] packToSend = { userID, field.getText() };
    155 
    156             try {
    157                 oos.writeObject(packToSend);
    158                 oos.flush();
    159             } catch (IOException ex) {
    160                 ex.printStackTrace();
    161             }
    162         }
    163     }
    164 
    165     /** 内部类,等待服务器发包的线程类。
    166      * 
    167      * @author mlxy
    168      * @version 0.8
    169      * */
    170     class ServerWaiter implements Runnable {
    171         public void run() {
    172             try {
    173                 ois = new ObjectInputStream(socket.getInputStream());
    174 
    175                 // 死循环,阻塞式地从服务器读包,之后更新文本框。
    176                 while (true) {
    177                     // 程序被readObject阻塞住的时候如果关闭框架会报错。之后解决。
    178                     String[] packReceived = (String[]) ois.readObject();
    179                     updateTextArea(packReceived[0], packReceived[1]);
    180                 }
    181             } catch (SocketException e) {
    182                 // 目前是简单粗暴地抓了异常就跳出程序。
    183                 System.out.println("Socket closed, client out.");
    184                 System.exit(-1);
    185             } catch (IOException e) {
    186                 e.printStackTrace();
    187             } catch (ClassNotFoundException e) {
    188                 e.printStackTrace();
    189             }
    190         }
    191     }
    192 }
    Client端
  • 相关阅读:
    机器学习-识别手写数字0-9
    tensorflow深度学习-mnist数据集读入-初试
    TensorFlow 2.0 最基础的线性回归
    cuDNN 环境变量-默认安装路径
    INT104-lab2
    [蓝桥杯][历届试题][dfs][割点]危险系数
    2021-03-19:给定一个二维数组matrix,其中的值不是0就是1,返回全部由1组成的最大子矩形,内部有多少个1。
    2021-03-17:手写代码:单链表插入排序。
    2021-03-16:手写代码:单链表归并排序。
    2021-03-15:手写代码:单链表选择排序。
  • 原文地址:https://www.cnblogs.com/chihane/p/3525856.html
Copyright © 2011-2022 走看看