首先将套接字添加到 epoll 集以进行边缘触发读取:
epoll_event ev = {};
ev.data.fd = sock;
ev.events = EPOLLIN | EPOLLET; // edge triggered reading
epoll_ctl(efd, EPOLL_CTL_ADD, sock, &ev);
现在等待数据:
result = epoll_wait(efd, events, sizeEvents, timeoutMilliseconds);
假设有 20+ 字节的可用数据。但后续代码想要以 10 字节块的形式解析流中的消息:
result = recv(sock, buffer, 10, 0);
所以此时,您可能会说,“如果他调用
epoll_wait
,即使套接字流中还有尚未读取的剩余 10 个字节,他的代码也可能会挂起或超时。”你是对的。
但是我的代码实际上切换了 epoll 标志,而不是返回 epoll_wait,这样它就可以在同一个套接字上发送响应。
ev.data.fd = sock;
ev.events = EPOLLOUT|EPOLLET;
epoll_ctl(efd, EPOLL_CTL_MOD, sock, &ev);
请注意,EPOLLIN 不再设置。然后代码执行
send
和 epoll_wait
的标准循环,直到发送完整响应。
设置消息响应后,代码将返回到边沿触发模式下读取:
ev.data.fd = sock;
ev.events = EPOLLIN | EPOLLET;
epoll_ctl(efd, EPOLL_CTL_MOD, sock, &ev);
接下来是等待:
result = epoll_wait(efd, events, sizeEvents, timeoutMilliseconds);
现在假设自上次从套接字读取以来没有其他数据到达
sock
,由于边缘级别没有改变,上述epoll_wait
是否挂起(或超时)?或者 EPOLLIN 再次关闭和打开的事实是否允许重置边缘状态,以便上述 epoll_wait
调用将立即返回以指示套接字上可用的数据?
切换受监控的事件仍会导致
epoll_wait()
挂起。 ET 模式下的 epoll_wait()
会对回调函数做出反应,当根据监视的事件对文件描述符进行更改时会触发该回调函数。您仍然需要等待一些新数据到达 fd
才能收到 epoll_wait()
通知。