What are the descriptor sets in each of these categories for? I don't understand the intent, why is it possible to write in readable set and read from writable set? What makes a socket write-ready?
In all the examples I've seen, the management of these groups is done manually, except for the read group. The question then is, why is it possible to write data in readable group? And why is it possible to read in the write group? Because then the meaning of these groups is lost and for each group it is necessary to write identical control logic?
Each of the sets is just that: a set of integers, with each integer in the set representing one socket that is part of that set. So you can't "read" or "write" from a set; you can only add integers to the set, or not add them, and then pass that set to
select().Note that that is completely different from the topic of calling
recv()orsend()on an individual socket itself, which you are allowed to do on any socket at any time, regardless of what you have placed into thefd_setsthat you passed toselect().The read-set specifies the sockets that you want to cause
select()to return, as soon as they are ready-for-read (i.e. as soon as at at least one of them has data that is ready for you to gather with a call torecv()).The write-set specifies the sockets that you want to cause
select()to return, as soon as they are ready-for-write (i.e. as soon as at at least one of them has outgoing-buffer-space available so that you could callsend()on it and place at least some data into its outgoing-data-buffer right away).The except-set is used (often in rather OS-specific ways) as a way to notify you that certain sockets have an exceptional condition present. I suggest ignoring this set for now and just passing NULL as its argument; you don't need it for most purposes.
A socket is write-ready when its outgoing-data-buffer is not completely full. (i.e. when you could call
send()on it andsend()would be able to place at least one byte of data into the buffer, and therefore would not have to block or return-1/EWOULDBLOCK)It's always possible(*) to call
send()orwrite()on any socket. That remains true even if you are also interested in havingselect()return when that socket is ready-for-read.It's always possible(*) to call
recv()orread()on any socket. That remains true even if you are also interested in havingselect()return when that socket is ready-for-write.That doesn't follow. The purpose of the
fd_setsis to express how you want theselect()call to behave -- in particular, what socket-states should causeselect()to return, and afterselect()has returned, to allow you to query the current ready-for-read/ready-for-write status of each socket. It is unrelated to what you actually do with the sockets afterselect()has returned; that remains entirely up to you.(*) note that "possible" doesn't necessarily imply "useful"; e.g. if you call
recv()on a socket that is not ready-for-read, then yourrecv()call will either block until some data arrives, or (if the socket is in non-blocking mode) it will immediately return-1/EWOULDBLOCK. Those behaviors might not be what you wanted.