Reputation: 2792
I am trying to understand the following code. If I have 50 connections to this server and I send data through one of these sockets, the select
block with the inner loop will capture what I send and echo it back. But what happens if within a very short time-frame of the first message, I send another one? So fast that the inner loop (after select
- the loop iterating over all active client sockets) doesn't finish. Will that data be thrown away? Will it be what the next select
will be triggered with? What happens if I send two messages before the inner loop finishes ? Will I ever face the scenario where inside the loop iterating over all the active sockets I get more than 1 that has "activity" - i.e.: can two FD_ISSET(sd, &readfds)
be true within a single iteration of the loop ?
Upvotes: 1
Views: 681
Reputation: 168
To add to the already excellent answers:
The select
function in this case isn't grabbing packets directly from the wire, it's actually going to the packet buffer, usually a part of the NIC, to grab packets/frames that are available to be read. The packet buffer is normally a ring buffer: it has a fixed size, new packets come in at the "top", and when the buffer gets full, the oldest packets drop out of the "bottom".
Just as @sam-varshavchik mentioned in the comments, as long as select is implemented correctly and the packet buffer doesn't clog up during the time you are going through the select
loop, you will be fine.
Here's an interesting article on how to implement a packet ring buffer for a socket.
Upvotes: 0
Reputation: 780974
Yes, multiple descriptors can be ready to read in a single iteration. The return value of select()
is the number of descriptors that are ready, and it can be more than 1. As you loop through the descriptors, you should increment a counter when FD_ISSET(sd, &readfds)
is true, and continue until the counter reaches this number.
But even if you only process one descriptor, nothing will be thrown away. select()
is not triggered by changes, it returns whenever any of the descriptors is ready to read (or write, if you also use writefds
). If a descriptor is ready to read, but you don't read from it, it will still be ready to read the next time you call select()
, so it will return immediately.
However, if you only process the first descriptor you find in the loop, later descriptors could be "starved" if an earlier descriptor is always ready to read, and you never process the later ones. So it's generally best to always process all the ready descriptors.
Upvotes: 3
Reputation: 154906
select()
is a level-triggered API, which means that it answers the question "are any of these file descriptors readable/writable now?", not "have these file descriptors become readable/writable?". That should answer most of your questions:
But what happens if within a very short time-frame of the first message, I send another one? [...] Will it be what the next
select
will be triggered with?
It will be what the next select()
will be triggered with.
What happens if I send two messages before the inner loop finishes ?
That depends on how long the messages are - TCP doesn't work in terms of messages, but in terms of a stream of bytes. The server might well read both messages in a single read()
. And if it doesn't, the socket will remain readable, and it will pick them up immediately on the next select()
.
Will I ever face the scenario where inside the loop iterating over all the active sockets I get more than 1 that has "activity" - i.e.: can two
FD_ISSET(sd, &readfds)
be true within a single iteration of the loop ?
Yes, if two clients send data at the same time (while you are out of select()
), select()
will report two readable file descriptors.
Upvotes: 1