【问题标题】:Can a socket be closed from another thread when a send / recv on the same socket is going on?当同一个套接字上的发送/接收正在进行时,可以从另一个线程关闭一个套接字吗?
【发布时间】:2010-08-28 06:24:37
【问题描述】:

当同一个套接字上的发送/接收正在进行时,可以从另一个线程关闭一个套接字吗?

假设一个线程正在阻塞recv调用,而另一个线程关闭了同一个socket,recv调用中的线程会知道这一点并安全出来吗?

我想知道不同操作系统/平台之间的行为是否会有所不同。如果是,它将在 Solaris 中表现如何?

【问题讨论】:

    标签: c sockets solaris


    【解决方案1】:

    在 linux 中关闭套接字不会唤醒 recv()。另外,正如@jxh 所说:

    如果在套接字关闭时线程在 recv() 或 send() 上被阻塞 通过不同的线程,被阻塞的线程将收到错误。 但是,很难检测到正确的补救措施 收到错误。这是因为文件描述符编号 与套接字关联的可能已经被另一个不同的 线程,并且被阻塞的线程现在已经被一个错误唤醒了 “有效”套接字。在这种情况下,被唤醒的线程不应该调用 close() 本身。

    被唤醒的线程需要一些方法来区分是否 错误是由连接产生的(例如网络错误) 要求它调用 close(),或者如果错误是由 不同的线程调用了 close() ,在这种情况下它应该 只是出错而不对套接字做任何进一步的事情。

    因此,避免这两个问题的最佳方法是调用shutdown() 而不是close()。 shutdown() 将使文件描述符仍然可用,因此不会被另一个描述符分配,也会以错误唤醒 recv() 并且带有 recv() 调用的线程可以以正常方式关闭套接字,就像发生了正常错误。

    【讨论】:

      【解决方案2】:

      我不知道 Solaris 网络堆栈的实现,但我会抛出我的理论/解释为什么它应该是安全的。

      • 线程 A 为这个给定的套接字进入一些阻塞系统调用,比如read(2)。套接字接收缓冲区中没有数据,因此线程 A 从处理器中取出并放入此套接字的等待队列中。此处未启动网络堆栈事件,连接状态(假设为 TCP)未更改。
      • 线程 B 在套接字上发出 close(2)。虽然在线程 B 访问内核套接字结构时应该锁定它,但没有其他线程持有该锁(线程 A 在进入睡眠等待时释放了锁)。假设套接字发送缓冲区中没有未完成的数据,则发送一个FIN 数据包并且连接进入FIN WAIT 1 状态(这里我再次假设TCP,参见connection state diagram)
      • 我猜套接字连接状态更改会为给定套接字上阻塞的所有线程生成唤醒。也就是说,线程 A 将进入可运行状态并发现连接正在关闭。如果对方没有发送自己的FIN,则可能会重新进入等待,否则系统调用将返回eof。

      在任何情况下,内部内核结构都将受到保护,不会受到不适当的并发访问。这并不意味着从多个线程执行套接字 I/O 是一个好主意。我建议研究非阻塞套接字、状态机和框架,如libevent。

      【讨论】:

        【解决方案3】:

        对我来说,来自另一个线程的 shutdown() 套接字在 Linux 中完成这项工作

        【讨论】:

        • 欢迎来到 stackoverflow.com。您可以通过提供对断言这一点的某种文档的引用或提供一个简短示例来改进您的答案。 “对你有用”的答案没有帮助,因为它可能对其他人不起作用。
        【解决方案4】:

        如果一个线程在recv() 或send() 上被阻塞,而套接字被另一个线程关闭,则被阻塞的线程将收到错误。然而,在收到错误后很难检测到正确的补救措施。这是因为与套接字关联的文件描述符编号可能已被另一个线程拾取,并且阻塞的线程现在已因“有效”套接字的错误而被唤醒。在这种情况下,被唤醒的线程应该不调用close()本身。

        被唤醒的线程需要某种方式来区分错误是由需要它调用close()的连接产生的(例如网络错误),还是由调用@987654325的不同线程产生的@ 就可以了,在这种情况下,它应该只是出错而不对套接字做任何进一步的事情。

        【讨论】:

          【解决方案5】:

          是的,可以从另一个线程关闭套接字。任何使用该套接字的阻塞/忙碌线程都将报告适当的错误。

          【讨论】:

          • 至少在 linux 中它似乎没有这样的报告。一个被阻塞的 recv 线程仍然被阻塞,即使我们从另一个线程调用 close。
          猜你喜欢
          • 1970-01-01
          • 2017-10-25
          • 2023-03-03
          • 2012-08-30
          • 1970-01-01
          • 2021-07-08
          • 1970-01-01
          • 1970-01-01
          • 2011-01-18
          相关资源
          最近更新 更多