最近在实现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