在进行send/recv操作的同时,另一个线程能否关闭同一socket?
假设一个线程正在阻塞地执行recv调用,而另一个线程关闭了相同的socket,那么正在执行recv调用的线程会知道这个情况并安全地退出吗?
我想知道,不同的操作系统/平台之间是否存在行为差异。如果有,Solaris将如何表现?
recv()
。 此外,正如@jxh所说:
如果一个线程在收到数据时被阻塞,但在此期间由不同的线程关闭了套接字,则被阻塞的线程将收到一个错误。 然而,很难在接收到错误之后检测到正确的补救措施。 这是因为与套接字相关联的文件描述符号可能已经被另一个线程拾取,并且阻塞的线程现在已经在对“有效”套接字的错误上被唤醒。 在这种情况下,被唤醒的线程不应该自己调用close()。
被唤醒的线程需要找到一种方法来区分错误是由连接(例如网络错误)生成的,需要它调用close(),还是错误是由其他线程在其上调用close()生成的,在这种情况下,它应该只是报错而不必执行对套接字的任何进一步操作。
因此,避免这两个问题的最佳方法是调用shutdown()
而不是close()
。 shutdown()
会使文件描述符仍然可用,因此不会被另一个描述符分配,还会唤醒recv()
并使调用recv()
的线程可以像处理普通错误一样正常关闭套接字。
read(2)
,对于给定的套接字。套接字接收缓冲区中没有数据,因此将线程A从处理器上移开,并将其放到等待此套接字的等待队列上。这里没有启动任何网络堆栈事件,连接状态(假设TCP)也没有改变。close(2)
。虽然内核套接字结构应该在线程B访问它时被锁定,但没有其他线程持有该锁(当线程A被放置到睡眠等待时,它释放了锁)。假设套接字发送缓冲区中没有未完成的数据,则会发送一个FIN
数据包并使连接进入FIN WAIT 1
状态(这里再次假设TCP,请参见连接状态图)FIN
,则等待可能会重新进入,否则系统调用将返回eof
。无论如何,内部内核结构都将受到保护,以防止不适当的并发访问。这并不意味着从多个线程进行套接字I/O是一个好主意。我建议研究非阻塞套接字、状态机和框架,例如libevent
。
对我来说,在 Linux 中从另一个线程 shutdown() 套接字就可以完成工作。
recv()
或send()
时,这个socket被另一个线程关闭了,那么这个线程将会收到一个错误。然而,在收到错误后,很难检测正确的补救措施。这是因为与该socket相关联的文件描述符号可能已经被另一个线程占用,此时被唤醒的线程通过一个“有效”的socket接收到了一个错误信息。在这种情况下,被唤醒的线程不应该自己去调用close()
方法。close()
方法;还是由另一个线程在它上面调用close()
方法引起的,则应该只是报告错误,而不做任何进一步处理。是的,从另一个线程关闭套接字是可以的。任何正在使用该套接字的阻塞/忙碌线程将报告适当的错误。