简体   繁体   English

Java聊天程序:客户端无法正确断开连接

[英]Java Chat Program: client not disconnecting properly

I'm trying to make a chat program for my one class, but the problem I am having is that, for example, if there are 3 clients: A,B, and C. They can all talk to each other fine but say client B disconnects, then A and C can no longer talk to each other. 我正在尝试为一个班级编写一个聊天程序,但是我遇到的问题是,例如,如果有3个客户:A,B和C。他们都可以互相交谈,但会说客户B断开连接,则A和C无法再互相通信。 I am storing my clients into a vector and I am not sure how to remove them upon disconnect. 我将客户存储在引导程序中,不确定在断开连接后如何将其删除。 However, I don't believe that's the problem. 但是,我不认为这是问题所在。 If someone could point me in the right direction for both issues that would be great! 如果有人能为我指出这两个问题的正确方向,那就太好了!

Server: 服务器:

public class Server {
    //vector to hold clients
    static Vector<RequestHandler> connected = new Vector<>();
    //client counter
    static int numClients = 0;
    //string to hold the server IP
    protected static String serverIP;

    public static void main(String[] args) throws IOException
    {
        //checks to see if port number was entered for server
        if(args.length < 1) 
        {
            System.err.println("Usage: java Server <port number>");
            System.exit(1);
        }

        System.out.println("Server started. Listening on Port 8005");
        //sets the port number to args passed in
        int portNumber = Integer.parseInt(args[0]);
        //declares executor to be used for thread gen
        ExecutorService executor = null;

        //tries to create new socket
        try(ServerSocket serverSocket = new ServerSocket(portNumber);) 
        {
            //creates thread pool w/ a thread for each client(# can vary)
            executor = Executors.newFixedThreadPool(10);
            System.out.println("Waiting for clients to connect...");

            while(true) 
            {
                //established socket connection
                Socket clientSocket = serverSocket.accept();
                RequestHandler worker = new RequestHandler(clientSocket);

                //adds client requesthandler to active client list
                connected.add(worker);
                //increments client counter
                numClients++;

                //starts new thread
                executor.execute(worker);

                System.out.println("Client " + numClients + " connected");
            }

        } catch (IOException e) {

            System.out.println("Exception caught when trying to listen on port "
                 + portNumber + " or listening for a connection");
            System.out.println(e.getMessage());

        } finally {
            if (executor != null) {
                executor.shutdown();
            }
        }
    }

    public static void notifyClients(RequestHandler sender, String clientMSG) throws IOException
    {
        System.out.println("Echoing Message to " + (numClients-1) + " clients...");

        for(RequestHandler tmp : connected)
        {

            if(!(tmp.equals(sender))) {
             tmp.sendMSG("client " + sender + ": " + clientMSG);
             System.out.println(sender + " wrote: \"" + clientMSG +
                     "\" to " + tmp);
            }

        }
    }



}

Request Handler: 请求处理程序:

public class RequestHandler implements Runnable {
    private final Socket client;
    ServerSocket serverSocket = null;

    public RequestHandler(Socket client) {
        this.client = client;
    }


    @Override
    public void run()
    {
        try(BufferedReader input = new BufferedReader(new InputStreamReader(client.getInputStream()));
                BufferedWriter output = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));) 
        {
            System.out.println("Thread started with name: " + Thread.currentThread().getName());
            String clientMsg;

            System.out.println("CLIENT: " + client);
            while((clientMsg = input.readLine())!= null) 
            {
                //removes special characters 
                clientMsg = clientMsg.replaceAll("[^A-Za-z0-9.?,:' ]", "");
                //prints message to server terminal
                //System.out.println("Received Message from " + Thread.currentThread().getName() + ": "+ clientMsg);
                System.out.println("Received Message from " + client.getPort()+ ": " + clientMsg);
                //sends message back to client that sent it
                Server.notifyClients(this, clientMsg);
                output.write("You entered: "+ clientMsg);
                output.newLine(); //new lines
                output.flush(); //clears output stream
            }

        } catch(IOException e) {

            System.out.println("Client " + Server.numClients + " disconnected.");
            Server.numClients--;
            System.out.println("IO Excpetion: " + e);
        } catch(Exception ex) {
            System.out.println("Exception in thread run. Exeption: " + ex);
        }

    }

    public void sendMSG(String msg) throws IOException {
             BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));  
             writer.write(msg);
             writer.newLine();
             writer.flush();
    }
}

The IOException from notifyClients that's raised when you attempt to send a message to a disconnected client is killing your run loop. 当您尝试向断开连接的客户端发送消息时, notifyClients引发的IOException正在杀死您的运行循环。

You should catch it and remove the offending client: 您应该抓住它并删除有问题的客户端:

// Synchronized set because we're in a multithreaded environment
static Set<RequestHandler> connected = Collections.synchronizedSet(new LinkedHashSet<>());

public static void notifyClients(RequestHandler sender, String clientMSG) {
    System.out.println("Echoing Message to " + (numClients - 1) + " clients...");

    // Defensive copy in case the client vector is modified while we iterate over it
    List<RequestHandler> connected;
    synchronized (Server.connected) {
        connected = new ArrayList<>(Server.connected);
    }

    for (RequestHandler client : connected) {
        try {
            if (!(client.equals(sender))) {
                client.sendMSG("client " + sender + ": " + clientMSG);
                System.out.println(sender + " wrote: \"" + clientMSG + "\" to " + client);
            }
        } catch (IOException e) {
            System.err.println("Couldn't write to " + client);
            Server.connected.remove(client);
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM