Reputation: 21104
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. However, I got "stuck" trying to understand the point of Selector
s for a client.
A selector supports key-based, non-blocking, multiplexed I/O. In other words, selectors enable you to perform I/O through multiple channels. (Java - The complete reference)
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? I think there is no point, am I right?
If my self-answer is right, why not using blocking I/O directly?
Upvotes: 2
Views: 425
Reputation: 4642
NIO
is basically used on the server side to handle large scale. 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).
A typical blocking
implementation goes like this:
Server accepts connection and puts it on the requests queue
.
A polling thread
consumes connections from the head of the queue and dispatches it to a thread pool
. The polling thread becomes free if the thread-pool
queue is not full and continues consuming connections from the queue
.
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
).
The requests queue
starts filling up in the meantime. 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.
Now consider this design:
The polling thread consumes items from the head of the requests queue.
It puts it on a unbounded list.
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. Note that these sockets
operate in the NIO
mode. That is, if there is no activity, our thread won't get blocked.
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. 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. But you will still be able to connect to the server, unlike in the previous design.
NIO
basically solves this problem by using selectors
.
Upvotes: 1