The NetBSD Project
”Of course it runs NetBSD”
本文翻译自:http://wiki.netbsd.org/tutorials/kqueue_tutorial/
NetBSD Wiki/tutorials/kqueue tutorial
目录
I、简介
II、kqueue API
- kevent 数据结构
- pair
- flags
- EV_SET()宏
2.kqueue()
3.kevent()
a.timeout
4.总结
III.例子
1.一个定时器例子
2.一个原始的TCP客户端例子
IV.参考文献
简介
本文档的目的是向程序员介绍kqueue的使用方法,而不是提供一个完整而详尽的文档。
Kqueue为应用程序提供了一个标准的API,用于注册他们感兴趣的各种事件和条件,并以有效的方式通知他们。它的设计是可伸缩,灵活,可靠和准确的。
Kqueue API
kevent数据结构
kevent结构体是这样的:
struct kevent
{
uintptr_t ident; /* identifier for this event */ 事件标识
short filter; /* filter for event */ 监听事件的类型,如EVFILT_READ,EVFILT_WRITE,EVFILT_TIMER等
u_short flags; /* action flags for kqueue */事件操作类型,如EV_ADD,EV_ENABLE,EV_DELETE等
u_int fflags; /* filter flag value */
intptr_t data; /* filter data value */
void *udata; /* opaque user data identifier */可携带的任意用户数据
};
pair
kevent 由一对<ident, filter>进行标识。标识符ident可以是一个描述符 (文件、套接字、流)、进程ID或信号量, 这取决于我们要监视的内容。筛选器filter标识用于处理相应事件的内核筛选器。有一些预先定义的系统筛选器 (如 EVFILT_READ 或 EVFILT_WRITE),当有可进行读取或写入操作的数据时,可分别被触发。
例如,如果我们想在socket有数据可读取时收到通知,我们必须指定一个<sckfd,EVFILLE_READ>形式的kevent,其中sckfd是与套接字关联的描述符。如果我们监视一个进程的活动,我们需要一个<pid,EVFILT_PROC>元组。需要注意的是,一个kqueue只能有一个<ident,filter>相同的kevent。
flags
在设计好一个kevent之后,我们应该决定是否将它添加到我们的kqueue中。为此,我们通过设置flags成员为EV_ADD。我们也可以通过设置EV_DELETE或EV_DISABLE来删除或仅仅只是禁用一个已存在的kevent。
可以通过或运算将期望的值组合在一起。例如,EV_ADD|EV_ENABLE|EV_ONESHOT将被解释为“添加这个事件,使能它并且只在第一次发生时被触发,在用户将事件从kqueue中取出之后将其删除。”
反过来,如果希望检查一个kevent中某个flag是否被置位,我们可以通过将kevent.flag与期望的值进行“与运算”。例如:
if(myevent.flags & EV_ERROR)
{
/*handle errors*/
}
EV_SET()宏
EV_SET()宏是为了便于初始化kevent结构体。我们暂时不祥述其余的kevent成员,相反我们先来看看当我们需要监视一个套接字是否有等待读取的数据的情况:
kevent ev;
EV_SET(&ev,sckfd,EVFILT_READ,EV_ADD,0,0,0);
如果我们要监视N个套接字的集合,我们应该这样写:
kevent ev[N];
int i;
for(i=0;i<N;i++)
{
EV_SET(&ev[i],sckfd[i],EVFILE_READ,EV_ADD,0,0,0);
}
kqueue
kqueue包含了我们所有趣的事件。因此,首先,我们必须创建一个新的kqueue,我们使用下面的代码执行此操作:
int kq;
if((q=kqueue())= = -1)
{