从客户端接收消息

时间:2017-02-01 22:42:19

标签: java sockets nonblocking

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

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
}

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

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

我的问题是:我需要另一个线程来执行此任务吗?有没有替代方案,例如非阻塞模式?

2 个答案:

答案 0 :(得分:1)

  

我的问题是:我是否需要另一个线程来执行此任务?

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

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?");
            }
        }
    }
}
  

是否有替代方案,例如非阻塞模式?

对于非阻塞套接字通道,服务器套接字必须向选择器注册才能执行某些操作。默认情况下,服务器套接字通道是阻塞通道。要使其成为非阻塞通道,请进行以下设置。

channel.configureBlocking(false);

非阻塞服务器程序看起来像......

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();
  ...
}

非阻塞客户端程序看起来像......

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();

答案 1 :(得分:0)

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

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

您可以在互联网上找到多线程服务器的多种实现,请查看此one