Python3 中 EPOLLHUP 事件是如何触发的?

如题。对端发送 close 关闭 socket,服务端的 EPOLLHUP 为啥不执行呢?
前提:没有被 IN/OUT 覆盖,我是把它写在 if 判断的第一个位置。我打印了 event 的值,发现只有 1(in)、4(out)、5( in | out),并没有发现 EPOLLHUP 16 的迹象。
dalao 们,有遇到过么,麻烦指点下
Python3 中 EPOLLHUP 事件是如何触发的?

9 回复

对端 close 的话 epoll 返回 EPOLLRDHUP
EPOLLHUP 是对端 reset 了连接(假设 tcp )


EPOLLHUP 事件在 Python 的 select.epoll 模块中表示“挂起”(hang-up),它通常由底层文件描述符的连接被关闭触发。具体来说,当对端关闭了连接(比如 TCP 连接的对端调用了 close()shutdown()),本地套接字会收到这个事件。在 epoll 中,EPOLLHUP 常常与 EPOLLINEPOLLRDHUP(如果支持)一起出现,表明连接已不可用。

在代码中,你可以这样检测 EPOLLHUP

import select
import socket

# 创建非阻塞 TCP 服务器套接字
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setblocking(0)
server.bind(('0.0.0.0', 8080))
server.listen(5)

epoll = select.epoll()
epoll.register(server.fileno(), select.EPOLLIN)

try:
    while True:
        events = epoll.poll(1)
        for fileno, event in events:
            if fileno == server.fileno():
                # 接受新连接
                conn, addr = server.accept()
                conn.setblocking(0)
                epoll.register(conn.fileno(), select.EPOLLIN)
            elif event & select.EPOLLHUP:
                # 连接被对端关闭
                print(f"Connection on fd {fileno} hung up")
                epoll.unregister(fileno)
                # 关闭套接字(这里需要从某个字典中获取套接字对象)
                # sock.close()
            elif event & select.EPOLLIN:
                # 可读事件处理
                pass
finally:
    epoll.unregister(server.fileno())
    epoll.close()
    server.close()

注意:EPOLLHUP 触发后,通常应该注销并关闭对应的套接字。实际应用中,你需要维护一个文件描述符到套接字对象的映射(比如用字典),以便在事件触发时能正确操作套接字。

简单总结:EPOLLHUP 表示连接被对端关闭,处理时记得清理资源。

epoll 主动 modify 触发

这个我知道,按道理是这样的,不过我在 python3.7 里面,就是不触发,哭

请问具体是如何 modify 的呢,在什么情况下

没写过 3 的, 但是处理过 py2.7 的, 估计大同小异 可以参考下我的连接池实现代码:

github.com/baidu/CUP/blob/master/cup/net/async/conn.py 重点是 poll 方法那一块



while not self._stopsign:
try:
events = self._epoll.poll(1)
except IOError as err:
if err.errno == errno.EINTR:
return
raise err
# log.debug(‘start to poll’)
for fileno, event in events:
# if it comes from the listen port, new conn
if fileno == self._bind_sock.fileno():
newsock, addr = self._bind_sock.accept()
self._handle_new_conn(newsock, addr)
elif event & select.EPOLLIN:
try:
self._handle_new_recv(self._fileno2context[fileno])
except KeyError:
log.info(‘socket already closed’)
elif event & select.EPOLLOUT:
try:
self._handle_new_send(self._fileno2context[fileno])
except KeyError:
log.info(‘socket already closed’)
elif (event & select.EPOLLHUP) or (event & select.EPOLLERR):
# FIXME: consider if we need to release net msg resources
if event & select.EPOLLHUP:
log.info(’–EPOLLHUP–’)
else:
log.info(’–EPOLLERR–’)
try:
self.cleanup_error_context(
self._fileno2context[fileno]
)
except KeyError:
log.info(‘socket already closed’)

V2EX 不知道怎么显示代码, 直接 github 看吧

好的,感谢

回到顶部