简体   繁体   English

非阻塞套接字客户端和选择器

[英]Non-blocking socket client and selectors

As I'd like to try and implement a basic TCP connection with Telegram servers (using MTProto), I started reading about the Java NIO classes.由于我想尝试实现与 Telegram 服务器的基本 TCP 连接(使用 MTProto),我开始阅读有关 Java NIO 类的信息。 However, I got "stuck" trying to understand the point of Selector s for a client.但是,我“卡住”了试图理解Selector对客户的意义。

A selector supports key-based, non-blocking, multiplexed I/O.选择器支持基于键的、非阻塞的、多路复用的 I/O。 In other words, selectors enable you to perform I/O through multiple channels.换句话说,选择器使您能够通过多个通道执行 I/O。 ( Java - The complete reference ) Java - 完整参考

Being that TCP messages, as a stream, are always ordered, and that I will only open a single socket connection (a single SocketChannel ), what is the point of using Selector s?由于 TCP 消息,作为 stream,始终是有序的,而且我只会打开单个套接字连接(单个SocketChannel ),使用Selector有什么意义? I think there is no point, am I right?我认为没有意义,对吗?

If my self-answer is right, why not using blocking I/O directly?如果我的自我回答是正确的,为什么不直接使用阻塞 I/O?

NIO is basically used on the server side to handle large scale. NIO基本上是用在服务器端来处理大规模的。 I'll try to explain how a typical server works.我将尝试解释典型服务器的工作原理。

A server has a requests queue, from which a polling thread consumes connections as a blocking dequeue operation (In Java, the default length of the requests queue is 50. It means if you try to initiate the 51st connection while the request queue is full, you'll get ConnectionRefused exception).服务器有一个请求队列,轮询线程从该队列中消耗连接作为blocking dequeue操作(在 Java 中,请求队列的默认长度为 50。这意味着如果您在请求队列已满时尝试启动第 51 个连接,你会得到ConnectionRefused异常)。

A typical blocking implementation goes like this:一个典型的blocking实现是这样的:

  1. Server accepts connection and puts it on the requests queue .服务器接受连接并将其放入requests queue

  2. A polling thread consumes connections from the head of the queue and dispatches it to a thread pool .轮询thread使用来自队列头部的连接并将其分派到thread pool The polling thread becomes free if the thread-pool queue is not full and continues consuming connections from the queue .如果thread-pool队列未满,轮询线程将变为空闲状态并继续使用queue中的连接。

  3. At some point, all the threads in the thread-pool will become busy and the polling thread will get blocked while submitting more connections to the pool (as the thread-pool queue is a blocking queue ).在某些时候,线程池中的所有线程都将变得忙碌,并且轮询线程将在向池提交更多连接时被阻塞(因为线程池队列是blocking queue )。

  4. The requests queue starts filling up in the meantime. requests queue同时开始填满。 At some point, it'll get completely full and the server will no longer accept any connections.在某些时候,它会完全充满,服务器将不再接受任何连接。

At this point, our server just can't scale anymore.在这一点上,我们的服务器无法再扩展。 Note that the "busy" threads in the pool might not be busy at all but just blocked - say for more data on the InputStream of the respective socket they are serving.请注意,池中的“忙碌”线程可能根本不忙,而只是被阻塞了——比如它们正在服务的相应套接字的InputStream上的更多数据。

Now consider this design:现在考虑这个设计:

  1. The polling thread consumes items from the head of the requests queue.轮询线程使用请求队列头部的项目。

  2. It puts it on a unbounded list.它把它放在一个无限列表中。

  3. Another thread continuously iterates over this list and checks if any activity has happened on the socket (read to read, ready to write, etc).另一个线程不断地遍历这个列表并检查套接字上是否发生了任何活动(读到读、准备写等)。 If there is an activity, the socket is served.如果有活动,则提供socket Note that these sockets operate in the NIO mode.请注意,这些socketsNIO模式下运行。 That is, if there is no activity, our thread won't get blocked.也就是说,如果没有活动,我们的线程不会被阻塞。

  4. The polling thread continues to submit connections to the list in the meantime as the list is unbounded.同时轮询线程继续向列表提交连接,因为列表是无限的。 It does not get blocked anywhere (except while it is waiting for a new connection on the requests queue).它不会在任何地方被阻塞(除非它在请求队列上等待新连接)。

In the above design, note that our scale is limited only by our system resources - namely how many connections the list hold.在上述设计中,请注意,我们的规模仅受系统资源的限制——即list拥有多少连接。 The response time will take a hit as there is just one thread servicing all the connections.响应时间会受到影响,因为只有一个线程为所有连接提供服务。 You CPU consumption will be pretty high due to the mindless iteration.由于盲目的迭代,您的 CPU 消耗将非常高。 But you will still be able to connect to the server, unlike in the previous design.但是您仍然可以连接到服务器,这与之前的设计不同。

NIO basically solves this problem by using selectors . NIO基本上通过使用selectors解决了这个问题。

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

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