每个类别中的描述符集有何用途?我不明白其意图,为什么可以在可读集中写入并从可写集中读取?是什么让套接字做好写准备?
在我见过的所有示例中,除了读取组之外,这些组的管理都是手动完成的。那么问题来了,为什么可以在可读组中写入数据呢?还有为什么写组里可以读呢?因为这样的话这些组的意义就丢失了,并且对于每个组都需要编写相同的控制逻辑?
为什么可以在可读集中写入并从可写集中读取?
每个集合就是:一组整数,集合中的每个整数代表属于该集合的一个套接字。所以你不能从集合中“读”或“写”;您只能将整数添加到集合中,也可以不添加它们。
请注意,这与在单个套接字本身上调用
recv()
或 send()
的主题完全不同,您可以随时在任何套接字上执行此操作,无论您将什么放入选择集中。
读取集指定您想要导致
select()
返回的套接字,一旦它们准备好读取(即,只要其中至少一个具有可供您收集的数据)致电 recv()
)。
写入集指定您想要导致
select()
返回的套接字,一旦它们准备好写入(即,只要其中至少一个具有可用的传出缓冲区空间,以便您可以调用 send()
并立即将至少一些数据放入其传出数据缓冲区中)。
使用 except-set(通常以特定于操作系统的方式)来通知您某些套接字存在异常情况。我建议暂时忽略这个集合,只传递 NULL 作为它的参数;大多数用途都不需要它。
什么使套接字可写?
当套接字的传出数据缓冲区未完全满时,套接字就处于写就绪状态。 (即,当您可以对其调用
send()
并且 send()
能够将至少一个字节的数据放入缓冲区时,因此不必阻塞或返回 -1/EWOULDBLOCK
)
那么问题来了,为什么可以在可读组中写入数据呢?
始终可以在任何套接字上调用
send()
或 write()
。即使您也有兴趣在该套接字准备好读取时返回 select()
,这仍然是正确的。
还有为什么写组里可以读?
始终可以在任何套接字上调用
recv()
或 read()
。即使您也有兴趣在该套接字准备好写入时返回 select()
,这仍然是正确的。
因为这样这些组的意义就丢失了,并且每个组都需要编写相同的控制逻辑?
事实并非如此。这些组的含义与您希望
select()
调用的行为方式相关 - 特别是,什么套接字状态应导致 select()
返回。它与您在 select()
返回后实际对套接字进行 do的操作无关;这取决于你。