Sockets: Select (readfds, writefds, exceptfds)

98 Views Asked by At

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?

1

There are 1 best solutions below

0
Jeremy Friesner On

why is it possible to write in readable set and read from writable set?

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() or send() on an individual socket itself, which you are allowed to do on any socket at any time, regardless of what you have placed into the fd_sets that you passed to select().

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 to recv()).

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 call send() 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.

What makes a socket write-ready?

A socket is write-ready when its outgoing-data-buffer is not completely full. (i.e. when you could call send() on it and send() 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)

The question then is, why is it possible to write data in readable group?

It's always possible(*) to call send() or write() on any socket. That remains true even if you are also interested in having select() return when that socket is ready-for-read.

And why is it possible to read in the write group?

It's always possible(*) to call recv() or read() on any socket. That remains true even if you are also interested in having select() return when that socket is ready-for-write.

Because then the meaning of these groups is lost and for each group it is necessary to write identical control logic?

That doesn't follow. The purpose of the fd_sets is to express how you want the select() call to behave -- in particular, what socket-states should cause select() to return, and after select() 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 after select() 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 your recv() 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.