如何关闭非阻塞套接字?

6

我相信如果我们在非阻塞套接字上调用close系统调用,它会立即返回,那么如何处理响应?无论它是关闭还是没有关闭? 换句话说,在非阻塞套接字上调用socket系统调用的行为是什么?


你使用的是哪个操作系统和编程语言? - Tony The Lion
Linux(FreeBSD)和C语言 - alexander
3个回答

8
不是套接字的阻塞状态,而是SO_LINGER选项很重要。从getsockopt(2)中可以得知:当套接字有未发送的消息排队并执行close(2)时,SO_LINGER控制采取的操作。如果套接字承诺可靠传输数据并设置了SO_LINGER,系统将在close(2)尝试上阻止进程,直到它能够传输数据或者决定无法传递信息(指定延迟间隔期,以秒为单位,在请求SO_LINGER时在setsockopt()系统调用中)。如果禁用了SO_LINGER并且发出了一个close(2),则系统将以使进程能够尽快继续进行的方式处理关闭。

也就是说,启用SO_LINGER,TCP套接字上的close(2)错误意味着内核无法在挂起时间内交付数据(不计算其他错误,如无效的文件描述符等)。禁用挂起 - 您永远不知道。另请参见The ultimate SO_LINGER page, or why is my tcp not reliable

1
所以你的意思是,如果一个带有正 linger 时间的 close 调用会阻塞,即使套接字被设置为非阻塞模式?我原本认为,在这种情况下,close 也不会阻塞,而 linger 时间只是在内核空间中套接字真正关闭之前可能经过的时间量,在用户空间中套接字立即关闭,因此对于非阻塞套接字,close 不会阻塞。 - Mecki
2
@Mecki 不会阻塞,如果有数据等待,则会返回-1,并带有 errno == EAGAIN/EWOULDBLOCK。这是一个非常模糊的领域。 - user207421

2
如果我们在非阻塞套接字上调用close系统调用,它会立即返回。该套接字始终处于关闭状态,但连接可能仍在向对等方写入。但是您的问题存在谬误:如果在任何套接字上调用close(),它都会立即返回。关闭套接字和向套接字写入是异步的。您可以通过SO_LINGER控制它,如其他答案所述,尽管我怀疑这仅适用于阻塞模式。如果需要这样做,可能应将套接字放回阻塞模式,然后使用正面的SO_LINGER关闭。

1
@user207421 - 你的回答是错误的。如果套接字处于阻塞模式,并且TCP窗口已满/写缓冲区已满,close()将会阻塞,因为FIN数据包需要SEQ和ACK号码。对于非阻塞套接字,你会得到EAGAIN错误。 然而,如果关闭no-lingering选项,close()将发送一个RST数据包而不是FIN数据包,并且不使用SEQ/ACK。RST数据包将立即发送,并且写缓冲区的内容将被简单地丢弃。SO_LINGER与阻塞或非阻塞模式没有任何关系。

尝试使用WSAsendDisconnect函数关闭套接字。 - Anmol kansal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接