Java:使用 AWT 按钮断开与聊天服务器的连接

Posted

技术标签:

【中文标题】Java:使用 AWT 按钮断开与聊天服务器的连接【英文标题】:Java: Using AWT button to disconnect from chat server 【发布时间】:2020-11-14 18:41:48 【问题描述】:

我正在编写一个简单的多线程客户端/服务器聊天系统。项目要求规定:“连接仅在单击连接按钮时发生。断开按钮应断开连接。用户应能够随意连接、断开连接、重新连接。”基本上,我已经连接并运行了连接按钮。但是,当我尝试断开连接时,我陷入了无限循环,其中客户端(在命令行上)无限打印“Sock closed”,而服务器端无限打印“Message read: null”。这导致我查看我的所有 for(;;) 循环以某种方式关闭其中的连接,但是我无法弄清楚如何关闭这些循环中的连接。请帮忙,这是我的第一个套接字编程项目,我对这个超级难过!谢谢大家。

客户:

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.ArrayList;

public class ClientFrame extends Frame
    public ClientFrame()
        setSize(500,500);
        setTitle("Chat Client");
        addWindowListener(new WindowAdapter()
            public void windowClosing(WindowEvent We)
                System.exit(0);
            
        );
        add(new ClientPanel(), BorderLayout.CENTER);        
        setVisible(true);
    
    public static void main(String[] args)
        new ClientFrame();
    

 // end ClientFrame

class ClientPanel extends Panel implements ActionListener, Runnable
    TextField tf;
    TextArea ta;
    List list;
    Button connect, disconnect;
    Socket socketToServer;
    PrintWriter pw;
    BufferedReader br;
    Thread t;
    String userName;

    public ClientPanel()
        setLayout(new BorderLayout());
        tf = new TextField();
        ta = new TextArea();
        list = new List();
        connect = new Button("Connect");
        disconnect = new Button("Disconnect");
        Panel bPanel = new Panel();
        bPanel.add(connect);
        disconnect.setEnabled(false);
        bPanel.add(disconnect);
        
        tf.addActionListener(this);
        add(tf, BorderLayout.NORTH);
        add(ta, BorderLayout.CENTER);
        add(list, BorderLayout.EAST);
        add(bPanel, BorderLayout.SOUTH);
        
        connect.addActionListener(this);
        disconnect.addActionListener(this);
    
     // end ClientPanel constructor


    public void actionPerformed(ActionEvent ae)
        if (ae.getSource() == tf)
            String temp = tf.getText();
            pw.println(userName+": "+temp);
            tf.setText("");
         else if (ae.getSource() == connect)
            if(tf.getText() == null || tf.getText().equals(""))
                    ta.append("Must enter a name to connect\n");
                else  
                    userName = tf.getText();
                    connect.setEnabled(false);
                    disconnect.setEnabled(true);
                    tf.setText("");     
                    try
                        socketToServer = new Socket("127.0.0.1", 3000);
                        pw = new PrintWriter(new OutputStreamWriter
                                (socketToServer.getOutputStream()), true);
                        br = new BufferedReader(new InputStreamReader
                                (socketToServer.getInputStream()));
                    catch(UnknownHostException uhe)
                        System.out.println(uhe.getMessage());
                    catch(IOException ioe)
                        System.out.println(ioe.getMessage());
                     
                

                    t = new Thread(this);
                    t.start();
                    pw.println(userName);
                    pw.println(userName +" has entered the chat.");
        else if (ae.getSource()== disconnect)
            try
                t.interrupt();
                socketToServer.close();
            catch(IOException ioe)
                System.out.println(ioe.getMessage());
            
        
     // end actionPerformed

    public void run()
            for(;;)
                try
                    String temp = br.readLine();
                    ta.append(temp + "\n");
                catch(IOException ioe)
                    System.out.println(ioe.getMessage());
                 
            
     // end run

 // end ClientPanel

服务器:

import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.awt.*;

public class ThreadedServerWithPresence  
    public static void main(String[] args)  
        ArrayList<ThreadedHandlerWithPresence> handlers;
            try    
            handlers = new ArrayList<ThreadedHandlerWithPresence>();
            ServerSocket s = new ServerSocket(3000);
                for(;;)  
                Socket incoming = s.accept( );
                new ThreadedHandlerWithPresence(incoming, 
                                    handlers).start();

               
            catch (Exception e)  
                System.out.println(e);
            
     


class ThreadedHandlerWithPresence extends Thread  

    Socket incoming;
    ArrayList<ThreadedHandlerWithPresence> handlers;
    PrintWriter pw;
    BufferedReader br;
    String userName;

    public ThreadedHandlerWithPresence(Socket i,
        ArrayList<ThreadedHandlerWithPresence> handlers) 
        incoming = i;
        this.handlers = handlers;
        handlers.add(this);
    

    public void setUserName(String userName)
        this.userName = userName;
    

    public String getUserName()
        return userName;
    
   
    public void run()  
        try    
            br = new BufferedReader(new InputStreamReader
                            (incoming.getInputStream()));

            pw = new PrintWriter(new OutputStreamWriter
                            (incoming.getOutputStream()),true);
           
            String firstLine = br.readLine();
            setUserName(firstLine);

            for(;;)
                
                String temp = br.readLine();

                System.out.println("Message read: " + temp);
        
                for(int i = 0; i < handlers.size(); i++)
                    handlers.get(i).pw.println(temp);
                
                       
            catch (Exception e)  
            System.out.println(e);
            finally
                handlers.remove(this); 
             
    

【问题讨论】:

【参考方案1】:

客户

您的 run 方法不处理中断,因此 for 循环不会结束,它会继续尝试接收消息。

您必须添加一个可以中断并抛出InterruptedException 的操作,在这种情况下 Thread.sleep 将是一个不错的选择,同时还可以降低 CPU 使用率(您不需要每时每刻都检查新消息)。

    try 
        for (; ; ) 
            try 
                String temp = br.readLine();
                ta.append(temp + "\n");

             catch (IOException ioe) 
                System.out.println(ioe.getMessage());

            
            Thread.sleep(10);
        
     catch (InterruptedException e) 
        System.out.println("Disconnected.");
    

服务器

br.readLine()返回null时,表示连接已被客户端关闭,您应该停止接收消息。

        String temp = br.readLine();

        if(temp == null)
            break;

【讨论】:

解决了!非常感谢!

以上是关于Java:使用 AWT 按钮断开与聊天服务器的连接的主要内容,如果未能解决你的问题,请参考以下文章

插件重新加载导致客户端与 IndexOutOfBoundsException 断开连接

用户的套接字与服务器断开连接后如何发送消息

C#多线程聊天服务器,处理断开连接

java UDP聊天与文件传输

java UDP聊天与文件传输

从聊天中获取待处理消息