将多个客户端连接到服务器的问题

时间:2019-06-29 11:13:54

标签: java server client

嘿,我正在编写一个带有服务器套接字和多个客户端的简单代码,服务器将获取每个客户端的用户名并将其存储在哈希图中。服务器接受套接字客户端,客户端输入用户名,但服务器又接受相同的套接字客户端,它希望使用其用户名,并且代码在此处停止。我希望它可用于多个客户端,而不仅仅是一个客户端。

服务器类:

example.com

客户端类:

public class Server implements Serializable{

    // [..]

    public void serverConnect() throws IOException, ClassNotFoundException
    {
        listener = new ServerSocket(9090);

        System.out.println("Server is running...");
        while (true)
        {
            System.out.println("Waiting ...");
            socket=listener.accept();
            for (Socket socket:socketList.keySet())
            {
                if (this.socket==socket)
                {
                checkSocket=false;
                }
            }
            if (checkSocket)
            {
            socketList.put(socket,socketNumber);
            System.out.println("Client is connected");
            inputReader = new InputStreamReader(socket.getInputStream());
            reader = new BufferedReader(inputReader);

            user = reader.readLine();
            Server.userList.add(user);
            socketNumber++;
            }
            checkSocket=true;
            }
    }
}

1 个答案:

答案 0 :(得分:0)

原则上,您可以使用单线程服务器(这意味着它一次只能接受一个客户端连接)。主要问题是您过于复杂地接收连接。

您可以通过将客户端连接套接字和读取器移至本地范围并直接处理套接字来进行处理,从而简化当前代码。

    public void serverConnect() throws IOException {
        listener = new ServerSocket(9090);
        System.out.println("Server is running...");

        while (true) {
            System.out.println("Waiting ...");
            Socket socket = listener.accept();

            try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
                String user = reader.readLine();
                Server.userList.add(user);
            } catch (IOException ignore) {
            } finally {
                socket.close();  
            }
        }
    }

您可以看到,除了读取发送的值外,您无需保持套接字状态。如果只希望客户端提供一行数据,则还应该关闭套接字,否则客户端可以通过在达到套接字超时之前不发送任何数据来保持服务器的人质。

此外,您还希望使用try / catch块将代码包装在while循环中,以防止异常终止服务器。

正如我在开篇中提到的那样,此代码可以作为单线程服务器使用,并且一次只能响应一个请求。如果要接受并处理多个请求,则需要生成一个新线程来处理响应。我建议您按以下方式构造您的代码,但是为了简洁起见,您可以执行以下操作:

    public void serverConnect() throws IOException {
        int MAX_WORKERS = 100;
        ExecutorService service = Executors.newFixedThreadPool(MAX_WORKERS);
        ServerSocket listener = new ServerSocket(9090);

        System.out.println("Server is running...");
        while (true) {
            System.out.println("Waiting ...");
            Socket socket = listener.accept();

            service.submit(() -> {
                System.out.println("Client is connected");
                try {
                    try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
                        String user = reader.readLine();
                        Server.userList.add(user);
                    } finally {
                        socket.close();
                    }
                } catch (Throwable ignore) {
                }
            });
        }
    }

因此,以上所有操作都是我们使用ExecutorService创建一个包含100个线程的线程池。从理论上讲,这意味着我们可以接受100个并发连接。

接受连接后,我们将套接字和工作程序代码提交给线程,这意味着主线程可以返回以侦听新的连接。