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