代码之家  ›  专栏  ›  技术社区  ›  Jay

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

  •  13
  • Jay  · 技术社区  · 14 年前

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

    假设一个线程在阻塞recv调用,另一个线程关闭同一个套接字,recv调用中的线程会知道这一点并安全地出来吗?

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

    5 回复  |  直到 14 年前
        1
  •  3
  •   Nikolai Fetissov    14 年前

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

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

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

        2
  •  10
  •   Community Jaime Torres    7 年前

    在linux中,关闭套接字不会唤醒 recv() . 同时,作为 @jxh

    通过另一个线程,被阻止的线程将收到一个错误。 接收错误。这是因为文件描述符编号 与插座相关的可能被另一个 线程,而被阻塞的线程现在已在一个 “有效”套接字。在这种情况下,唤醒的线程不应该调用 close()本身。

    错误是由连接(例如网络错误)生成的 不同的线程调用了close(),在这种情况下它应该 只是在没有对套接字做任何进一步操作的情况下出错。

    所以避免这两个问题的最好方法就是打电话 shutdown() close() . 关机() 会使文件描述符仍然可用,所以不会被另一个描述符分配,也会被唤醒 接收() 错误的线程

        3
  •  2
  •   bam    11 年前

        4
  •  1
  •   jxh    10 年前

    如果线程被阻塞 recv() send() 当套接字被另一个线程关闭时,被阻止的线程将收到一个错误。但是,在收到错误后很难检测到正确的补救措施。这是因为与套接字相关联的文件描述符号可能已经被另一个线程获取,并且被阻止的线程现在已经被一个“有效”套接字的错误唤醒。在这种情况下,唤醒的线程应该 呼叫 close()

    唤醒的线程需要某种方法来区分错误是否是由需要它调用的连接(例如网络错误)生成的 关闭() ,或者错误是由调用 在它上面,在这种情况下,它应该只是出错,而不需要对套接字做任何进一步的操作。

        5
  •  0
  •   Remy Lebeau    14 年前

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