从客户端接收消息

Receiving messages from Client

我编写了以下连接到客户端的服务器:

ServerSocket server = null;

try
{
    server = new ServerSocket(4040);

    while (isServerListening)
    {
        Socket clientSocket = server.accept();

        // Send bytes to the Client
        ServerOutputStream = clientSocket.getOutputStream();

        byte[] bytes = "I am a Server".getBytes();
        ServerOutputStream.write(bytes);
    }
}
catch (IOException e)
{
    e.printStackTrace();
}
finally
{
    // close socket here
}

此服务器在第 server.accept() 行停止并等待下一个客户端连接。同时我想读取从客户端收到的消息。

几年前我用不同的语言通过事件处理程序进行了套接字编程,但在这里我似乎需要一种不同的方法。

我的问题是:我需要另一个线程来完成这项任务吗?有没有其他选择,例如非阻塞模式?

您可以创建一个线程池并将 clientSocket 作为新任务提交给 ThreadPool

Socket clientSocket = serverSocket.accept();
threadPool.submit(new ClientTask(clientSocket)); 

您可以在互联网上找到 multi-threaded 服务器的多个实现,查看此 one

My question is: Would I need another thread for this task?

一种方法是为每个客户端连接使用一个线程。应用程序方法在监听端口的无限循环中运行服务器。当请求连接时,它会生成一个新线程来提供服务并立即 returns 进行监听。

ServerSocket listener = new ServerSocket(9898);
try {
    while (true) {
        new Handler(listener.accept(), clientNumber++).start();
    }
 } finally {
     listener.close();
 }

处理特定套接字上的请求的线程。

private static class Handler extends Thread {
    private Socket socket;
    private int clientNumber;

    public Handler(Socket socket, int clientNumber) {
        this.socket = socket;
        this.clientNumber = clientNumber;
    }

    public void run() {
        try {
            BufferedReader in = new BufferedReader(
                    new InputStreamReader(socket.getInputStream()));
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

            while (true) {
                String input = in.readLine();
                ...
            }
        } catch (IOException e) {
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                log("Couldn't close a socket, what's going on?");
            }
        }
    }
}

Is there an alternative e.g. non-blocking mode?

使用 non-blocking 套接字通道,服务器套接字必须向选择器注册才能执行某些操作。默认情况下,服务器套接字通道是阻塞通道。要使其成为 non-blocking 频道,请设置以下内容。

channel.configureBlocking(false);

Non-blocking 服务器程序看起来像...

InetAddress hostIPAddress = InetAddress.getByName("localhost");
int port = 19000;
Selector selector = Selector.open();
ServerSocketChannel channel = ServerSocketChannel.open();
channel.configureBlocking(false);
channel.socket().bind(new InetSocketAddress(hostIPAddress, port));
channel.register(selector, SelectionKey.OP_ACCEPT);

while (true) {
  Set keys = selector.selectedKeys();
  ...
}

non-blocking 客户端程序看起来像...

InetAddress serverIPAddress = InetAddress.getByName("localhost");
InetSocketAddress serverAddress = new InetSocketAddress(
    serverIPAddress, 19000);
Selector selector = Selector.open();
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
channel.connect(serverAddress);
int operations = SelectionKey.OP_CONNECT | SelectionKey.OP_READ
    | SelectionKey.OP_WRITE;
channel.register(selector, operations);

while (true) {
  if (selector.select() > 0) {
    Set keys = selector.selectedKeys();
    ...
  }
}
channel.close();