EVFILT_WRITE重复触发咨询:调用send/write后再次触发是否正常?
关于kqueue EVFILT_WRITE重复触发的问题解答
这个现象是完全符合预期的行为,核心原因在于kqueue中EVFILT_WRITE过滤器的触发逻辑:
EVFILT_WRITE的触发本质:它的触发条件是「文件描述符的发送缓冲区有可用空间」,也就是描述符处于可写入状态。当你调用
send或write发送数据后,如果发送缓冲区没有被完全填满(或者发送操作没有因为缓冲区满而返回EAGAIN/EWOULDBLOCK),那么该描述符依然满足可写入的条件,kqueue就会再次触发EVFILT_WRITE事件。EV_CLEAR标志的局限:你配置的
EV_CLEAR只会在事件被处理后清除当前的事件状态,但它无法阻止后续符合条件的事件触发。只要描述符持续处于可写入状态,kqueue就会持续推送该事件。正确的处理逻辑:如果希望避免EVFILT_WRITE重复触发,你需要在数据发送完成(或暂时无数据可发)时,手动禁用该过滤器,等到下次有新数据需要发送时再重新启用。示例代码如下:
if (e->filter == EVFILT_WRITE) { ssize_t sent_bytes = send(socket, buff, strlen(buff), 0); // 处理发送结果,比如判断是否发送完成、处理错误 if (sent_bytes == strlen(buff)) { // 数据全部发送完毕,禁用WRITE事件 struct kevent change; EV_SET(&change, socket, EVFILT_WRITE, EV_DISABLE, 0, 0, NULL); kevent(kq, &change, 1, NULL, 0, NULL); } }
另外需要注意:如果send返回的字节数小于预期长度(即部分数据发送成功),你需要记录剩余未发送的数据,后续继续在EVFILT_WRITE事件中发送,直到全部数据发送完成后再禁用事件。
内容的提问来源于stack exchange,提问作者hanerik jansen
相关产品推荐
相关产品推荐

