Jay*_*Jay 13 c sockets solaris
当同一个套接字上的send/recv正在进行时,是否可以从另一个线程关闭套接字?
假设一个线程在阻塞recv调用而另一个线程关闭同一个套接字,recv调用中的线程是否会知道这个并安全地出来?
我想知道不同OS /平台之间的行为是否会有所不同.如果是,它在Solaris中的表现如何?
在Linux中,关闭套接字不会唤醒recv()
。另外,正如@jxh所说:
如果在套接字被其他线程关闭时在recv()或send()上阻塞了线程,则阻塞的线程将收到错误。但是,在收到错误后很难检测到正确的补救措施。这是因为与套接字相关联的文件描述符号可能已经由另一个线程获取,并且现在由于“有效”套接字的错误而唤醒了被阻塞的线程。在这种情况下,唤醒的线程不应调用close()本身。
唤醒的线程将需要某种方法来区分错误是由要求它调用close()的连接生成的(例如,网络错误),还是该错误是由对其上调用close()的其他线程生成的,在这种情况下,它应该只是出错,而无需对套接字做任何进一步的操作。
因此,避免这两个问题的最佳方法是致电shutdown()
而不是close()
。shutdown()
将使文件描述符仍然可用,因此不会被另一个描述符分配,还会唤醒recv()
并显示错误,并且带有recv()
调用的线程可以正常方式关闭套接字,就像发生了正常错误一样。
我不知道 Solaris 网络堆栈的实现,但我会放弃我的理论/解释为什么它应该是安全的。
read(2)
线程 A为这个给定的套接字输入一些阻塞系统调用,例如。套接字接收缓冲区中没有数据,因此线程 A 从处理器中取出并放入该套接字的等待队列中。这里没有发起网络堆栈事件,连接状态(假设 TCP)没有改变。close(2)
在套接字上出现问题。虽然内核套接字结构在线程 B 访问它时应该被锁定,但没有其他线程持有该锁(线程 A 在进入睡眠等待状态时释放了该锁)。假设套接字发送缓冲区中没有未完成的数据,则FIN
发送数据包并且连接进入该FIN WAIT 1
状态(我再次假设此处为 TCP,请参阅连接状态图)FIN
,则可能会重新进入等待,否则系统调用将返回eof
。无论如何,内部内核结构都将受到保护,免受不适当的并发访问。这并不意味着从多个线程执行套接字 I/O 是个好主意。我建议研究非阻塞套接字、状态机和框架,例如libevent
.