简体   繁体   English

如何避免使用Java ServerSocket阻塞?

[英]How can I avoid blocking with Java ServerSocket?

Im working on a socket listener that has to listen on 2 ports for 2 types of data( port 80 and port 81). 我正在研究一个套接字监听器,它必须在2个端口上侦听2种类型的数据(端口80和端口81)。 These data are very similar as in the kind of operations that are performed on the data and are just different because they arrive n different ports. 这些数据与对数据执行的操作类型非常相似,只是因为它们到达不同的端口而不同。 I went ahead and coded an implementation using Java's ServerSocket class, only to realize later that the accept() method of the ServerSocket class is block and my implementation cant afford that. 我继续使用Java的ServerSocket类编写实现,但后来才意识到ServerSocket类的accept()方法是块,我的实现无法承受。 So now i was thinking of implementing the same using Java NIO but after having gone through some tutorials i think i am more confused than how i started. 所以现在我正在考虑使用Java NIO实现相同的功能,但在完成了一些教程之后,我认为我比我开始时更困惑。 It would be great if someone here could walk me through the whole process, even of it be in pseudo code or jus technical "what to do next"'s. 如果这里的某个人可以引导我完成整个过程,即使它是伪代码或技术“下一步该做什么”,那将是很棒的。 This is what i plan to achieve. 这就是我打算实现的目标。

Listen, like for ever on 2 ports by calling 2 similar threads.(non blocking) A remote device from some network location connects, sends data and then disconnects. 通过调用2个类似的线程来监听,就像永远在2个端口上一样。(非阻塞)来自某个网​​络位置的远程设备连接,发送数据然后断开连接。

I think if only knowledge of how NIO can be used to set up a server to listen on a port say port 80, on localhost,is achieved, the rest is all pretty easy to implement. 我想如果只知道如何使用NIO设置服务器来监听端口,那么就可以实现localhost上的端口80,其余的都很容易实现。

Cheers 干杯

Here a little example to get started with NIO. 这里有一个开始使用NIO的小例子。

It's a server listening on ports 80 and 81 and printing everything that is received on standard output. 它是一个侦听端口80和81的服务器,并打印标准输出上接收的所有内容。 A connection is closed after receiving a packet starting with CLOSE ; 收到以CLOSE开头的数据包后CLOSE ; the whole server is shutdown after receiving a packet starting with QUIT . 收到以QUIT开头的数据包后,整个服务器都会关闭。 Missing the sending part and error handling could be a bit better. 缺少发送部分和错误处理可能会好一点。 :-) :-)

public static void main() throws IOException {
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    Selector selector = Selector.open();

    ServerSocketChannel server1 = ServerSocketChannel.open();
    server1.configureBlocking(false);
    server1.socket().bind(new InetSocketAddress(80));
    server1.register(selector, OP_ACCEPT);

    ServerSocketChannel server2 = ServerSocketChannel.open();
    server2.configureBlocking(false);
    server2.socket().bind(new InetSocketAddress(81));
    server2.register(selector, OP_ACCEPT);

    while (true) {
        selector.select();
        Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
        while (iter.hasNext()) {
            SocketChannel client;
            SelectionKey key = iter.next();
            iter.remove();

            switch (key.readyOps()) {
                case OP_ACCEPT:
                    client = ((ServerSocketChannel) key.channel()).accept();
                    client.configureBlocking(false);
                    client.register(selector, OP_READ);
                    break;
                case OP_READ:
                    client = (SocketChannel) key.channel();
                    buffer.clear();
                    if (client.read(buffer) != -1) {
                        buffer.flip();
                        String line = new String(buffer.array(), buffer.position(), buffer.remaining());
                        System.out.println(line);
                        if (line.startsWith("CLOSE")) {
                            client.close();
                        } else if (line.startsWith("QUIT")) {
                            for (SelectionKey k : selector.keys()) {
                                k.cancel();
                                k.channel().close();
                            }
                            selector.close();
                            return;
                        }
                    } else {
                        key.cancel();
                    }
                    break;
                default:
                    System.out.println("unhandled " + key.readyOps());
                    break;
            }
        }
    }
}

Obs : the fields of SelectionKey ( OP_ACCEPT ...) are statically imported: ObsSelectionKeyOP_ACCEPT ...)的字段是静态导入的:

import static java.nio.channels.SelectionKey.*;

NIO is called for when you need to scale to many thousands of simultaneous connections. 当您需要扩展到数千个同时连接时,需要NIO。

Otherwise, I'd suggest using multiple threads. 否则,我建议使用多个线程。 For each port (and its corresponding ServerSocket ), create a thread that calls accept() in a loop. 对于每个端口(及其对应的ServerSocket ),创建一个在循环中调用accept()的线程。 These calls will block, but that is alright because other threads are running, taking care of any available tasks. 这些调用会阻塞,但这没关系,因为其他线程正在运行,负责任何可用的任务。

When a new Socket is accepted, create another thread that is dedicated to that connection. 接受新Socket ,创建专用于该连接的另一个线程。 It depends on the application, but typically this thread will read from the socket (a blocking operation), and perform the requested operation, writing the results back to the socket. 它取决于应用程序,但通常此线程将从套接字读取(阻塞操作),并执行请求的操作,将结果写回套接字。

This architecture will scale to many hundreds of connections on most desktop platforms. 在大多数桌面平台上,此体系结构将扩展到数百个连接。 And the programming model is fairly simple, as long as each connection is self-contained and independent of the others (this avoids concurrency issues). 编程模型非常简单,只要每个连接都是独立的并且独立于其他连接(这可以避免并发问题)。 Introducing NIO will provide more scalability, but requires a lot of complexity. 引入NIO将提供更多可扩展性,但需要很多复杂性。

Many frameworks, such as Apache MINA and Netty , have been implemented based on Java NIO to boost non-blocking IO programming. 许多框架,例如Apache MINANetty ,都是基于Java NIO实现的,以增强非阻塞IO编程。 I strongly recommend them to make your NIO programming a joy, rather than a nightmare. 我强烈建议他们让你的NIO编程变得快乐,而不是噩梦。 They fit your problem. 他们适合你的问题。

In addition, try to use an efficient protocol both in transport message size and encode/decode (serialize/deserialize) performance. 此外,尝试在传输消息大小和编码/解码(序列化/反序列化)性能中使用有效的协议。 Google Protocol Buffers is a reliable solution in this area. Google Protocol Buffers是该领域的可靠解决方案。 Also take a look at Kryo and KryoNet . 还可以看看KryoKryoNet They can be helpful. 他们可以提供帮助。

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

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