手把手教你写一个Java在线聊天系统

手把手教你写一个Java在线聊天系统

标签: Java Toy_Programm Thread Swing/AWT


东软2016暑假实训内容,之前写过,这次想按自己思路独立写一遍。


1. Let’s Chat V0.1

  • 创建一个窗口,起一个客户端ChatClient.java
  • extends Frame
  • 设置客户端标题,可见性,位置,大小,窗口关闭形式

    private void launchFrame() {
        this.setTitle("Let's Chat");
        this.setBounds(100, 100, 400, 300);
        //这样写,可以在关闭窗口时,做资源回收的当作
        this.addWindowListener(new WindowAdapter(){
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }           
        });
        this.setVisible(true);
    }
    

2. Let’s Chat V0.2

  • 添加文本域
    • TextField
    • TextArea
  • 设置TextField在BorderLayout.SOUTH
  • 设置TextArea在BorderLayout.NORTH

当我尝试使用JTextField和JTextArea达不到TextField和TextArea的效果,所以我使用后者。

this.pack();//消除组件之间的间隙

3. Let’s Chat V0.3

  • 往TextField里输入,输出到TextArea里

这里我们想当按下ENTER时达到这种效果,采用事件与监听器

  • 为TextField添加一个监听器

    常规写法,或者我们可以单独写一个类,如果方法里,代码太长,就应该写一个内部类

     tf.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
                ta.setText(tf.getText().trim());
                tf.setText("");
            }
    });
    

这里的接口ActionListener只有一个方法,就是函数式接口,所以这里我们可以采用Lambda编程

    tf.addActionListener((e)->{
        ta.setText(tf.getText().trim());
        tf.setText("");
    });

4. Let’s Chat V0.4

  • 起一个服务器端ChatServer.java,基于TCP的
  • 服务器端

注意捕捉异常

private ServerSocket ss = null;
private Socket s = null;
ss = new ServerSocket(9600);
s = ss.accept();

 - 服务器重复打开,占用同一端口
 - IOException
  • 开启服务器,开启客户端,两者能连上
  • 客户端

注意捕捉异常

private Socket s = null;
s = new Socket("127.0.0.1",9600);

 - 服务器未打开,先打开客户端
 - IOException

5. Let’s Chat V0.5

  • 客户端输入一句话,服务端能收到
  • 服务器端

    private DataInputStream dis = null;
    dis = new DataInputStream(s.getInputStream());
    String str = dis.readUTF();
    
  • 客户端

    private DataOutputStream dos = null;
    dos = new DataOutputStream(s.getOutputStream());
    dos.writeUTF(str);
    dos.flush();
    

    6. Let’s Chat V0.6

  • 客户端不断输入一句话,服务器能收到
    使用while(true) {}

    while(true) {   
        dis = new DataInputStream(s.getInputStream());
        String str = dis.readUTF();
        System.out.println(str);
    }
    

我们注意到关闭客户端会报一些异常,这是因为我们没有在关掉窗口时对资源进行关闭回收

  1. 关闭客户端,服务器端SocketException
  2. 关闭服务器,一旦尝试输入,服务器端SocketException

    这里我们对其作简单处理,即在出现异常的地方,捕捉它,输出一个提示信息,然后退出程序

    catch (SocketException se) {
    System.out.println(“A Server quit…”);
    System.exit(0);
    }
    7. Let’s Chat V0.7

    • 多个客户端能够连上服务器端

采用两个死循环,外层不断侦听并接受到此套接字的连接,内层不断读取字符。实际运行我们发现无论如何都只能连接一个客户端。这是应为readUTF()是一个阻塞性函数,所以main()会一直阻塞在这里。

while(true) {   
    s = ss.accept();
    while(true) {   
        dis = new DataInputStream(s.getInputStream());
        String str = dis.readUTF();
        System.out.println(str);
    }
}

思路:把内层循环里读取字符的动作封装成一个线程(这意味着程序要做很大的更改)。

8. Let’s Chat V0.8

  • 服务器端能够把信息发送给每一个客户端,并且客户端能接收

  1. 客户端能接收
    起一个线程,不断地读取字符

    public void run() {
        try {
            while(conned) {
                dis = new DataInputStream(s.getInputStream());
                String str = dis.readUTF();
                ta.setText(ta.getText()+str+"\n");      
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
  2. 服务器端能够把信息发送给每一个客户端
    为了达到这个目的,我们需要把每一个线程的信息都保存,于是我们想到用泛型ArrayList来实现。
    所以服务器端需要做的就是,在每读取到字符时,都给每个客户端发一遍。

    for(int i=0 ; i

9. Let’s Chat V0.9
做最后的进一步完善

  1. 当关闭一个客户端时,从ArrayList里remove(this)
    注:移除了,但是,还是会报一些异常,我做捕捉,但是并未处理。

    1. 设置窗口不可改大小
    2. 文本TextArea不可编辑
    3. 添加发送信息时的时间

    4. 添加了一些注释

后期添加功能

监听线程
数据端口和控制端口,不同端口号
好的处理关闭方法
告诉服务器端客服端要关闭了,服务器端做资源关闭处理
客户端信息
给每一个客户端一个名字,单独聊天(私聊),群聊
传文件
传表情,文件之类的

注:github源码

你可能感兴趣的:(系统,Java,多线程,Swing,GUI)