kqueue演示样例
网络server通常都使用epoll进行异步IO处理,而开发人员通常使用mac,为了方便开发。我把自己的handy库移植到了mac平台上。
移植过程中,网上竟然没有搜到kqueue的使用样例。让我吃惊不已。为了让大家不用像我一样再次花费大力气搞定kqueue,我整理了一个简单清晰可执行的kqueue样例,供大家參考。
kqueue一共同拥有几个函数:
int kqueue(void); //相似epoll_create
int kevent(int kq, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout); //兼具epoll_ctl及epoll_wait功能
EV_SET(&kev, ident, filter, flags, fflags, data, udata); //设定kevent參数的宏
struct kevent {
uintptr_t ident; /* identifier for this event */
int16_t filter; /* filter for event */
uint16_t flags; /* general flags */
uint32_t fflags; /* filter-specific flags */
intptr_t data; /* filter-specific data */
void *udata; /* opaque user data identifier */
};
函数调用演示样例:
//创建kqueue
int epollfd = kqueue();
//加入或者改动fd
struct kevent ev[2];
int n = 0;
if (events & kReadEvent) {
EV_SET(&ev[n++], fd, EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, (void*)(intptr_t)fd);
} else if (modify){
EV_SET(&ev[n++], fd, EVFILT_READ, EV_DELETE, 0, 0, (void*)(intptr_t)fd);
}
if (events & kWriteEvent) {
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD|EV_ENABLE, 0, 0, (void*)(intptr_t)fd);
} else if (modify){
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_DELETE, 0, 0, (void*)(intptr_t)fd);
}
printf("%s fd %d events read %d write %d\n",
modify ?
"mod" : "add", fd, events & kReadEvent, events & kWriteEvent);
int r = kevent(efd, ev, n, NULL, 0, NULL);
//获取ready的fd
struct timespec timeout;
timeout.tv_sec = waitms / 1000;
timeout.tv_nsec = (waitms % 1000) * 1000 * 1000;
const int kMaxEvents = 20;
struct kevent activeEvs[kMaxEvents];
int n = kevent(efd, NULL, 0, activeEvs, kMaxEvents, &timeout);
//处理IO事件
for (int i = 0; i < n; i ++) {
int fd = (int)(intptr_t)activeEvs[i].udata;
int events = activeEvs[i].filter;
if (events == EVFILT_READ) {
handleRead(efd, fd);
} else if (events == EVFILT_WRITE) {
handleWrite(efd, fd);
}
}
注意kevent与epoll最大的不同在于READ/WRITE事件是分开注冊而且分开返回的,而Epoll则是一个fd一次返回读和写事件,用标志位来推断。
能够执行的代码例如以下:kqueue-example(handy对kqueue提供了封装版本号)
#include <sys/socket.h>
#include <sys/event.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#define exit_if(r, ...) if(r) {printf(__VA_ARGS__); printf("error no: %d error msg %s\n", errno, strerror(errno)); exit(1);}
const int kReadEvent = 1;
const int kWriteEvent = 2;
void setNonBlock(int fd) {
int flags = fcntl(fd, F_GETFL, 0);
exit_if(flags<0, "fcntl failed");
int r = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
exit_if(r<0, "fcntl failed");
}
void updateEvents(int efd, int fd, int events, bool modify) {
struct kevent ev[2];
int n = 0;
if (events & kReadEvent) {
EV_SET(&ev[n++], fd, EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, (void*)(intptr_t)fd);
} else if (modify){
EV_SET(&ev[n++], fd, EVFILT_READ, EV_DELETE, 0, 0, (void*)(intptr_t)fd);
}
if (events & kWriteEvent) {
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD|EV_ENABLE, 0, 0, (void*)(intptr_t)fd);
} else if (modify){
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_DELETE, 0, 0, (void*)(intptr_t)fd);
}
printf("%s fd %d events read %d write %d\n",
modify ? "mod" : "add", fd, events & kReadEvent, events & kWriteEvent);
int r = kevent(efd, ev, n, NULL, 0, NULL);
exit_if(r, "kevent failed ");
}
void handleAccept(int efd, int fd) {
struct sockaddr_in raddr;
socklen_t rsz = sizeof(raddr);
int cfd = accept(fd,(struct sockaddr *)&raddr,&rsz);
exit_if(cfd<0, "accept failed");
sockaddr_in peer, local;
socklen_t alen = sizeof(peer);
int r = getpeername(cfd, (sockaddr*)&peer, &alen);
exit_if(r<0, "getpeername failed");
printf("accept a connection from %s\n", inet_ntoa(raddr.sin_addr));
setNonBlock(cfd);
updateEvents(efd, cfd, kReadEvent|kWriteEvent, false);
}
void handleRead(int efd, int fd) {
char buf[4096];
int n = 0;
while ((n=::read(fd, buf, sizeof buf)) > 0) {
printf("read %d bytes\n", n);
int r = ::write(fd, buf, n); //写出读取的数据
//实际应用中。写出数据可能会返回EAGAIN,此时应当监听可写事件。当可写时再把数据写出
exit_if(r<=0, "write error");
}
if (n<0 && (errno == EAGAIN || errno == EWOULDBLOCK))
return;
exit_if(n<0, "read error"); //实际应用中,n<0应当检查各类错误,如EINTR
printf("fd %d closed\n", fd);
close(fd);
}
void handleWrite(int efd, int fd) {
//实际应用应当实现可写时写出数据,无数据可写才关闭可写事件
updateEvents(efd, fd, kReadEvent, true);
}
void loop_once(int efd, int lfd, int waitms) {
struct timespec timeout;
timeout.tv_sec = waitms / 1000;
timeout.tv_nsec = (waitms % 1000) * 1000 * 1000;
const int kMaxEvents = 20;
struct kevent activeEvs[kMaxEvents];
int n = kevent(efd, NULL, 0, activeEvs, kMaxEvents, &timeout);
printf("epoll_wait return %d\n", n);
for (int i = 0; i < n; i ++) {
int fd = (int)(intptr_t)activeEvs[i].udata;
int events = activeEvs[i].filter;
if (events == EVFILT_READ) {
if (fd == lfd) {
handleAccept(efd, fd);
} else {
handleRead(efd, fd);
}
} else if (events == EVFILT_WRITE) {
handleWrite(efd, fd);
} else {
exit_if(1, "unknown event");
}
}
}
int main() {
short port = 99;
int epollfd = kqueue();
exit_if(epollfd < 0, "epoll_create failed");
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
exit_if(listenfd < 0, "socket failed");
struct sockaddr_in addr;
memset(&addr, 0, sizeof addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
int r = ::bind(listenfd,(struct sockaddr *)&addr, sizeof(struct sockaddr));
exit_if(r, "bind to 0.0.0.0:%d failed %d %s", port, errno, strerror(errno));
r = listen(listenfd, 20);
exit_if(r, "listen failed %d %s", errno, strerror(errno));
printf("fd %d listening at %d\n", listenfd, port);
setNonBlock(listenfd);
updateEvents(epollfd, listenfd, kReadEvent, false);
for (;;) { //实际应用应当注冊信号处理函数。退出时清理资源
loop_once(epollfd, listenfd, 10000);
}
return 0;
}
kqueue演示样例的更多相关文章
- Python Web框架Tornado的异步处理代码演示样例
1. What is Tornado Tornado是一个轻量级但高性能的Python web框架,与还有一个流行的Python web框架Django相比.tornado不提供操作数据库的ORM接口 ...
- JDBC连接MySQL数据库及演示样例
JDBC是Sun公司制定的一个能够用Java语言连接数据库的技术. 一.JDBC基础知识 JDBC(Java Data Base Connectivity,java数据库连接)是一种用 ...
- java 覆盖hashCode()深入探讨 代码演示样例
java 翻盖hashCode()深入探讨 代码演示样例 package org.rui.collection2.hashcode; /** * 覆盖hashcode * 设计HashCode时最重要 ...
- 模式识别 - 处理多演示样例学习(MIL)特征(matlab)
处理多演示样例学习(MIL)特征(matlab) 本文地址: http://blog.csdn.net/caroline_wendy/article/details/27206325 多演示样例学习( ...
- java并行调度框架封装及演示样例
參考资料: 阿里巴巴开源项目 CobarClient 源代码实现. 分享作者:闫建忠 分享时间:2014年5月7日 ---------------------------------------- ...
- Java连接redis的使用演示样例
Java连接redis的使用演示样例 Redis是开源的key-value存储工具,redis通经常使用来存储结构化的数据,由于redis的key能够包括String.hash.listset和sor ...
- Introspector(内省)简单演示样例 与 简单应用
简单演示样例: package com.asdfLeftHand.test; import java.beans.BeanDescriptor; import java.beans.BeanInfo; ...
- libcurl使用演示样例
简要说明:C++使用libcurl訪问"www.baidu.com".获取返回码和打印出http文件 /* * @ libcurl使用演示样例 * @ 2014.04.29 * @ ...
- 构造Scala开发环境并创建ApiDemos演示样例项目
从2011年開始写Android ApiDemos 以来.Android的版本号也更新了非常多,眼下的版本号已经是4.04. ApiDemos中的样例也添加了不少,有必要更新Android ApiDe ...
随机推荐
- HDU 4351
求某区间各个子集的和的根的最大的五个数. 子集根其实就是这个数模9后的余数,注意的是要区分0和9,两者的余数都是0.. 记录前i个数的和的根,设为sum数组,然后处理两个数组 lft[i][j]表示从 ...
- NEFU 119
和上一题一样,注意除不尽为0 #include <iostream> #include <cstdio> #include <cstring> #include & ...
- JS 推断URL中是否含有 http:// 假设没有则自己主动为URL加上
url = url.substr(0,7).toLowerCase() == "http://" ? url : "http://" + url; 记性不大好. ...
- Spark SQL with Hive
前一篇文章是Spark SQL的入门篇Spark SQL初探,介绍了一些基础知识和API,可是离我们的日常使用还似乎差了一步之遥. 终结Shark的利用有2个: 1.和Spark程序的集成有诸多限制 ...
- Batch Normalization的算法本质是在网络每一层的输入前增加一层BN层(也即归一化层),对数据进行归一化处理,然后再进入网络下一层,但是BN并不是简单的对数据进行求归一化,而是引入了两个参数λ和β去进行数据重构
Batch Normalization Batch Normalization是深度学习领域在2015年非常热门的一个算法,许多网络应用该方法进行训练,并且取得了非常好的效果. 众所周知,深度学习是应 ...
- Oracle 优化和性能调整
分析评价Oracle数据库性能主要有数据库吞吐量.数据库用户响应时间两项指标.数据库用户响应时间又可以分为系统服务时间和用户等待时间两项,即: 数据库用户响应时间=系统服务时间+用户等待时间 因此 ...
- React中多行文本省略不生效原因
在普通的前端项目中,在不考虑兼容问题的时候,可以用以下代码实现: overflow : hidden; text-overflow: ellipsis; display: -webkit-box; - ...
- SparkSQL 与 Spark Core的关系
不多说,直接上干货! SparkSQL 与 Spark Core的关系 Spark SQL构建在Spark Core之上,专门用来处理结构化数据(不仅仅是SQL). Spark SQL在Spark C ...
- Spark编程模型几大要素
不多说,直接上干货! Spark编程模型几大要素 Driver Program 输入-Transformation-Action 缓存 共享变量
- JavaScript系列--浅析原型链与继承
一.前言 继承是面向对象(OOP)语言中的一个最为人津津乐道的概念.许多面对对象(OOP)语言都支持两种继承方式::接口继承 和 实现继承 . 接口继承只继承方法签名,而实现继承则继承实际的方法.由于 ...