kqueue用法简介

什么是kqueue和IO复用

kqueue是在UNIX上比较高效IO复用技术。    
所谓的IO复用,就是同时等待多个文件描述符就绪,以系统调用的形式提供。如果所有文件描述符都没有就绪的话,该系统调用阻塞,否则调用返回,允许用户进行后续的操作。
常见的IO复用技术有select, poll, epoll以及kqueue等等。其中epoll为Linux独占,而kqueue则在许多UNIX系统上存在。

相关的数据结构

kqueue有三个主要的东西:struct kevent结构体,EV_SET宏以及kevent函数。

struct kevent结构体是用于调度的事件
// struct kevent结构体
struct kevent {
    // 该事件关联的文件描述符,如socket中的fd句柄
    uintptr_t       ident;
    /* 
     * 可以指定监听类型
     * 如EVFILT_READ=读,EVFILT_WRITE=写,EVFILT_TIMER=定时器事件,EVFILT_SIGNAL=信号,EVFILT_USER=用户自定义事件
     */
    int16_t         filter;     
    /**
     * 操作方式
     * EV_ADD 添加,EV_DELETE 删除,EV_ENABLE 激活,EV_DISABLE 不激活
     */
    uint16_t        flags;
    uint32_t        fflags;         /* 第二种操作方式,NOTE_TRIGGER 立即激活等等 */
    intptr_t        data;           /* int 型的用户数据,socket 里面它是可读写的数据长度 */
    void            *udata;         /* 指针类型的数据,你可以携带任何想携带的附加数据。比如对象 */
};

EV_SET 是用于初始化kevent结构的便利宏
EV_SET(&kev, ident, filter, flags, fflags, data, udata);

kevent函数
int kevent(int kq,                      // kqueue的句柄
    const struct kevent *changelist, // 是 kevent 的数组,就是一次可以添加多个事件
    int nchanges, // 是 changelist 数组长度
    struct kevent *eventlist, // 是待接收事件的数组,里面是空的,准备给 kqueue 放数据的
    int nevents, // 是 eventlist 数组长度,传了 eventlist参数后,kevent() 将会阻塞等待事件发生才返回,返回的全部事件在 eventlist 数组里面。
    const struct timespec *timeout); // 是阻塞超时时间,超过这个时间就不阻塞了,直接返回

使用kqueue

#include <sys/event.h>
#include <sys/types.h>
// 引入头文件

int kq = kqueue();
// 获取kqueue句柄

struct kevent evt;    // 创建
EV_SET(&evt, sock, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL);  // 赋值
kevent(kq, &evt, 1, NULL, 0, NULL);    // 添加
// 创建并添加监听事件


struct kevent events[Max_Event_Count];
int ret = kevent(kq, NULL, 0, events, Max_Event_Count, NULL); 
// 监听事件的发生

// kevent() 是阻塞调用,等到有事件才返回。阻塞时进程处于sleep状态,有事件时系统激活kqueue,kevent()返回
// events 是 kqueue 返回的事件数组

参考:https://www.freebsd.org/cgi/man.cgi?kqueue


ethread
425 声望14 粉丝

一不小心做了码农的历史迷