ILD

tcp poll() no POLLHUP when remote side's socket closed
作者:Yuan Jianpeng 邮箱:yuanjp89@163.com
发布时间:2022-11-30 站点:Inside Linux Development

最近在实现xproxy的时候,想要用poll(),监视远程套接字的关闭,根据man手册。可以events等于0,在revents中监视POLLHUP。

但是测试,远端套接字关闭的时候,没有POLLHUP事件,如果监听POLLIN,则有POLLIN事件,此时read()返回0,read之后,再监听POLLIN事件,还是有POLLIN事件返回。也就说对于远端关闭的套接字,poll()会持续触发POLLIN事件。


抓包分析之后,发现套接字close,默认是gracefully close。它会发送FIN,然后对端ACK。此时half closed。所以不会触发POLLHUP。

可以用shutdown(fd, SHUT_RD/SHUT_WR/SHUT_RDWR)。来实现关闭。


shutdown(fd, SHUT_WR)将单独关闭本端的写,本端发送FIN,此时write将导致SIGPIPE。


测试发现,只有两端都FIN,且套接字没close的情况下,会上报POLLHUP事件。


对于pipe,由于是单向,可能情况不通。unix domain socket情况也可能不同。


另外还有一个linger选项。

struct linger linger = { .l_onoff = 1, .l_linger = 0 };

setsockopt(ctrl_sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));

可以设置close的时候,立即发送tcp rst,这样就会触发POLLHUP,此时不是优雅的关闭,缓存中的数据也会丢掉。

如果是client发送数据给server,发送完就close,此时不能用此选项,要优雅关闭,保证内核把缓存中的数据送出去。


其实监视远端关闭的正确的选项是监听 POULLRDHUP 事件。


参考:

https://stackoverflow.com/questions/72668918/recv-call-returns-0-vs-pollhup-event-in-c-poll

https://stackoverflow.com/questions/17705239/is-there-a-way-to-detect-that-tcp-socket-has-been-closed-by-the-remote-peer-wit


Copyright © linuxdev.cc 2017-2024. Some Rights Reserved.