libevent下载可以用于串口吗

下次自动登录
现在的位置:
& 综合 & 正文
基于libevent2.0的ministored的http框架–server端
将Ministored从libevent1.4升级到2.0以后,花了两天额外的时间来做调试这个http的框架。
按照开发的设想,这个ministored支持四个基本的操作put、get、delete、status;在经过几个版本的改动以后,协议如下:
1)数据通过post的方式提交
2)各个基本操作通过一个自定义的Http的头method来区分。而client和server之间的传送的二进制数据通过base64编码以后的字符串发送。数据附加在post操作提交的字符缓冲区中。
2.1 put操作需要的数据key value,解码以后,按照key和value的大小直接二进制拷贝,server并不关心数据的具体类型
2.2 get操作接收client发送的key,解码,取出对应的数据以后,base64编码,发送给client
2.3 delete操作接收client发送的key,解码,删除数据
2.4 status操作直接返回当前Ministore状态的描述字符串
3)各个操作的结果通过自定义的响应头"result"返回
下面是部分的代码,限于篇幅,就不完全展开了。
【上篇】【下篇】当前位置:&&
本页文章导读:
&&&&?ios界面基础&&&&&&1.uiview是所有界面元素的父类,包括uiwindow
2.UIView是iOS系统中界面元素的基础,所有的界面元素都继承自它,它真正的绘图部分,是由一个叫CALayer(Core
Animation Layer)的类来管理。UIView本身,.........&&&&?libevent-2.0.21笔记&&&&&&参看http://www.wangafu.net/~nickm/libevent-book/ &和libevent-2.0.21源码
其中有部分我认为比较简单的,就没有记录在这里了。
关于源码,可以主要关注,evutil.c evbuffer.c event.c bufferevent.c bufferevent_sock.c .........&&&&?[Java Tips] How to Use StringTokenizer in Java?&&&&&&The string tokenizer class allows an application to break a string into tokens. A token is returned by taking a substring of the string that was used to create the StringTokenizer object. There are three ways to construct a StringTokenizer.
public cla.........
[1]ios界面基础
&&&&来源:&互联网& 发布时间:&
1.uiview是所有界面元素的父类,包括uiwindow
2.UIView是iOS系统中界面元素的基础,所有的界面元素都继承自它,它真正的绘图部分,是由一个叫CALayer(Core
Animation Layer)的类来管理。UIView本身,更像是一个CALayer的管理器,访问它的跟绘图和跟坐标有关的属性,例如frame,bounds等等,实际上内部都是在访问它所包含的CALayer的相关属性。
3.FRAME, BOUNDS和CENTER属性之间的关系:
frame:描述当前视图在其父视图中的位置和大小。&
bounds:描述当前视图在其自身坐标系统中的位置和大小。&
center:描述当前视图的中心点在其父视图中的位置。&
ios采用CGPoint来表示点在坐标系上X、Y位置。我们可以通过CGPointMake(x,y)来创建一个坐标点:CGPoint point = CGPointMake(80,40)
同时,ios采用CGSize来表示视图的宽度和高度,即视图的大小。我们可以通过CGSizeMake(width,height)来创建一个矩形的大小,如CGSize size = CGSizeMake(144,72)将创建一个宽度为144,高度为72的矩形大小。
而CGRect则是结合了CGPoint和CGSize,用来表示矩形的位置和大小。它的origin表示矩形右上角所在位置(CGPoint),size表示矩形的大小(CGSize)。
回到frame和bounds属性,通过前面的描述不难发现,这两个属性都是用来描述视图的大小(CGSize)和位置(CGPoint)的,两者都用CGRect表示。不同的是,frame描述的是在其父视图中的CGRect,而bounds描述的是在其自身视图中的CGRect,也就是说,两者所在的坐标系是不同的。如图3所示,View B是View A的子视图,那么,View B的frame属性为origin(200,100),size(200,250),而View B的bounds属性为origin(0,0),size(200,250)。
一般来说,bounds属性比较少用,通常使用frame来设置视图的大小和位置,使用center来改变(移动)视图的位置(也可用frame来改变位置)。另外,对视图进行旋转、缩放也都是相对于center进行操作的。
UIView的bounds属性:
其类型为:CGrect,bounds.origin一般值为(0,0),bounds.size为当前view的宽高。
UIView的frame属性:
其类型也为CGrect, frame.origin一般值为当前view的顶点位于父view的坐标值。frame.size同样为当前view的宽高。
4.UIView的CALayer类似UIView的子View树形结构,也可以向它的layer上添加子layer,来完成某些特殊的表示。例如下面的代码:
CALayer *backLayer = [CALayer
& & backLayer.backgroundColor = [[UIColor
orangeColor] colorWithAlphaComponent:0.1].CGC
& & backLayer.bounds = CGRectMake(10,
//设置layer的区域
& & backLayer.position = CGPointMake(1024/2,
768/2-10);
//设置layer坐标
& & [self.view.layer
addSublayer:backLayer];
会在目标View上敷上一层橙色的透明薄膜。
5.要支持layer操作,必须加入QuartzCore.framework库的支持,在项目属性的build phases页面的link binary with libraries中添加
& 然后加入头文件:
#import &QuartzCore/QuartzCore.h&
6.假如我创建了两个UIView, 分别是A和B,&&那么 [A addSubview:B]&&和 [A.layer addSublayer: B.layer] 有什么区别:
如果你做[A
addSubview:B],B.layer会自动被加到A.layer的sublayers里去。
[2]libevent-2.0.21笔记
&&&&来源:&互联网& 发布时间:&
参看http://www.wangafu.net/~nickm/libevent-book/ &和libevent-2.0.21源码
其中有部分我认为比较简单的,就没有记录在这里了。
关于源码,可以主要关注,evutil.c evbuffer.c event.c bufferevent.c bufferevent_sock.c 这几个文件。
-------------------------------笔记---------------------------
用event_base_new 创建struct&event_base *base ,
在bind,listen完后,
用event_new 创建struct&event *listener_event用于监听是否有链接到达
通过event_add 将event添加到base中
在处理连接到达函数中添加读写event
event_base_dispatch(base),进行启动,其实就是个循环
event_free释放event
使用内置bufferevent,会自动收发数据,有点像preactor
从监听处理函数开始有变化,在监听处理函数中这么做:
struct bufferevent *
evutil_make_socket_nonblocking(fd);
bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(bev, readcb, NULL, errorcb, NULL);//设置读写回调
bufferevent_setwatermark(bev, EV_READ, 0, MAX_LINE);
bufferevent_enable(bev, EV_READ|EV_WRITE);//设置bev关心的事件之后只要在读回调函数中取到bufferevent内部的input,output指针然后evbuffer_* 函数读取数据,而要发送数据只要将数据通过evbuffer_add添加到output,释放bufferevent 通过调用bufferevent_free
设置libevent在complie libevent的时候指定CFLAGS=-DUSE_DEBUG可以取到底层更详细的loglog函数设置event_set_log_callback,log开关event_enable_debug_logging,log level标志要使用最新的,_开头的已被弃用fatal error默认调用exit或abort,不过也可以用event_set_fatal_callback设置自己的fatal函数,不过要注意如果调用过自己的处理函数后,不能在调用libevent 任何函数
默认情况多线程是不支持的(即没有设置lock,condition等),如果要使libevent支持多线程,在event_base_new前面要调下面函数int evthread_use_windows_threads(void);//win上设置
int evthread_use_pthreads(void);&&&&//unix上设置
如果lock有错误可以通过evthread_enable_lock_debugging进行捕捉,通过assert会exit调试event使用event_enable_debug_mode在使用bufferevent时,如果在创建bufferevent的时候,指定了BEV_OPT_THREADSAFE,那么new bufferevent过程的内部函数会调用buffereven
[3][Java Tips] How to Use StringTokenizer in Java?
&&&&来源:&互联网& 发布时间:&
The string tokenizer class allows an application to break a string into tokens. A token is returned by taking a substring of the string that was used to create the StringTokenizer object. There are three ways to construct a StringTokenizer.
public class Program {
public static void main(String[] args) {
System.out.println(&Case 1.&);
StringTokenizer st = new StringTokenizer(&this is a test&);
while (st.hasMoreTokens()) {
System.out.println(st.nextToken());
System.out.println(&Case 2.&);
st = new StringTokenizer(&this,is a=test&, & ,=&);
while (st.hasMoreTokens()) {
System.out.println(st.nextToken());
System.out.println(&Case 3.&);
st = new StringTokenizer(&this,is a=test&, & ,=&, true);
while (st.hasMoreTokens()) {
System.out.println(st.nextToken());
System.out.println(&Case 4.&);
st = new StringTokenizer(&this,is a=test&, & ,=&, false);
while (st.hasMoreTokens()) {
System.out.println(st.nextToken());
}The output is
StringTokenizer is pretty straight forward. You can separate a String by any delimiters that you choose such as a blank space, or a comma. Once you create a StringTokenizer object with a String, like above example. You can call nextToken() to get the next block
of String (token).
StringTokenizer helps me remember the same utility i used in shell and php language before. In shell, we use IFS environment variable and for loop to break &one string variable into array. Meanwhile, we can use explode method to parse the string into array
with the designed delimiters.
作者:wonderfan 发表于 11:19:06 原文链接
阅读:29 评论:0 查看评论
最新技术文章:
特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!
(C)2012-,E-mail:www_169it_(请将#改为@)名词解释:man epoll之后,得到如下结果: NAME
epoll - I/O event notification facility SYNOPSIS
#include &sys/epoll.h& DESCRIPTION
epoll is a variant of poll(2) that can be used either as Edge or Level
Triggered interface and scales well to large numbers of
are provided to set up and control an epoll set:
epoll_create(2), epoll_ctl(2), epoll_wait(2).
An epoll set is connected to a file descriptor created
epoll_cre-
Interest for certain file descriptors is then registered via
epoll_ctl(2).
Finally, the actual wait is started by epoll_wait(2). 其实,一切的解释都是多余的,按照我目前的了解,EPOLL模型似乎只有一种格式,所以大家只要参考我下面的代码,就能够对EPOLL有所了解了,代码的解释都已经在注释中: while (TRUE)
int nfds = epoll_wait (m_epoll_fd, m_events, MAX_EVENTS, EPOLL_TIME_OUT);//等待EPOLL时间的发生,相当于监听,至于相关的端口,需要在初始化EPOLL的时候绑定。
if (nfds &= 0)
m_bOnTimeChecking = FALSE;
G_CurTime = time(NULL);
for (int i=0; i& i++)
if (m_events[i].data.fd == m_listen_http_fd)//如果新监测到一个HTTP用户连接到绑定的HTTP端口,建立新的连接。由于我们新采用了SOCKET连接,所以基本没用。
OnAcceptHttpEpoll ();
else if (m_events[i].data.fd == m_listen_sock_fd)//如果新监测到一个SOCKET用户连接到了绑定的SOCKET端口,建立新的连接。
OnAcceptSockEpoll ();
else if (m_events[i].events & EPOLLIN)//如果是已经连接的用户,并且收到数据,那么进行读入。
OnReadEpoll (i);
OnWriteEpoll (i);//查看当前的活动连接是否有需要写出的数据。
catch (int)
PRINTF ("CATCH捕获错误/n");
m_bOnTimeChecking = TRUE;
OnTimer ();//进行一些定时的操作,主要就是删除一些短线用户等。
}  其实EPOLL的精华,按照我目前的理解,也就是上述的几段短短的代码,看来时代真的不同了,以前如何接受大量用户连接的问题,现在却被如此轻松的搞定,真是让人不得不感叹。 今天搞了一天的epoll,想做一个高并发的代理程序。刚开始真是郁闷,一直搞不通,网上也有几篇介绍epoll的文章。但都不深入,没有将一些注意的地方讲明。以至于走了很多弯路,现将自己的一些理解共享给大家,以少走弯路。
epoll用到的所有函数都是在头文件sys/epoll.h中声明,有什么地方不明白或函数忘记了可以去看一下。
epoll和select相比,最大不同在于:
1epoll返回时已经明确的知道哪个sokcet fd发生了事件,不用再一个个比对。这样就提高了效率。
2select的FD_SETSIZE是有限止的,而epoll是没有限止的只与系统资源有关。
1、epoll_create函数 函数声明:int epoll_create(int size) 该函数生成一个epoll专用的文件描述符。它其实是在内核申请一空间,用来存放你想关注的socket fd上是否发生以及发生了什么事件。size就是你在这个epoll fd上能关注的最大socket fd数。随你定好了。只要你有空间。可参见上面与select之不同2.
22、epoll_ctl函数
函数声明:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
该函数用于控制某个epoll文件描述符上的事件,可以注册事件,修改事件,删除事件。
epfd:由 epoll_create 生成的epoll专用的文件描述符;
op:要进行的操作例如注册事件,可能的取值EPOLL_CTL_ADD 注册、EPOLL_CTL_MOD 修 改、EPOLL_CTL_DEL 删除
fd:关联的文件描述符;
event:指向epoll_event的指针;
如果调用成功返回0,不成功返回-1
用到的数据结构
typedef union epoll_data {
void * __uint32_t u32; __uint64_t u64; } epoll_data_t;
struct epoll_event { __uint32_ /* Epoll events */ epoll_data_ /* User data variable */ };
struct epoll_ //设置与要处理的事件相关的文件描述符 ev.data.fd= //设置要处理的事件类型 ev.events=EPOLLIN|EPOLLET; //注册epoll事件 epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);
常用的事件类型: EPOLLIN :表示对应的文件描述符可以读; EPOLLOUT:表示对应的文件描述符可以写; EPOLLPRI:表示对应的文件描述符有紧急的数据可读 EPOLLERR:表示对应的文件描述符发生错误; EPOLLHUP:表示对应的文件描述符被挂断; EPOLLET:表示对应的文件描述符有事件发生;
3、epoll_wait函数 函数声明:int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout) 该函数用于轮询I/O事件的发生; 参数: epfd:由epoll_create 生成的epoll专用的文件描述符; epoll_event:用于回传代处理事件的数组; maxevents:每次能处理的事件数; timeout:等待I/O事件发生的超时值(单位我也不太清楚);-1相当于阻塞,0相当于非阻塞。一般用-1即可 返回发生事件数。
#include &stdio.h&
#include &stdlib.h&
#include &errno.h&
#include &string.h&
#include &sys/types.h&
#include &netinet/in.h&
#include &sys/socket.h&
#include &sys/wait.h&
#include &unistd.h&
#include &arpa/inet.h&
#include &openssl/ssl.h&
#include &openssl/err.h&
#include &fcntl.h&
#include &sys/epoll.h&
#include &sys/time.h&
#include &sys/resource.h&
#define MAXBUF 1024
#define MAXEPOLLSIZE 10000
setnonblocking - 设置句柄为非阻塞方式
int setnonblocking(int sockfd)
if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1)
return -1;
handle_message - 处理每个 socket 上的消息收发
int handle_message(int new_fd)
char buf[MAXBUF + 1];
/* 开始处理每个新连接上的数据收发 */
bzero(buf, MAXBUF + 1);
/* 接收客户端的消息 */
len = recv(new_fd, buf, MAXBUF, 0);
if (len & 0)
("%d接收消息成功:'%s',共%d个字节的数据/n",
new_fd, buf, len);
if (len & 0)
("消息接收失败!错误代码是%d,错误信息是'%s'/n",
errno, strerror(errno));
close(new_fd);
return -1;
/* 处理每个新连接上的数据收发结束 */
/************关于本文档********************************************
*filename: epoll-server.c
*purpose: 演示epoll处理海量socket连接的方法
*wrote by: zhoulifa(&a href="mailto:"&&/a&) 周立发(&a href=""&&/a&)
Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言
*date time: 21:00
*Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途
* 但请遵循GPL
*Thanks to:Google
*Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力
* 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献!
*********************************************************************/
int main(int argc, char **argv)
int listener, new_fd, kdpfd, nfds, n, ret,
struct sockaddr_in my_addr, their_
unsigned int myport,
struct epoll_
struct epoll_event events[MAXEPOLLSIZE];
myport = 5000;
lisnum = 2;
/* 设置每个进程允许打开的最大文件数 */
rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE;
if (setrlimit(RLIMIT_NOFILE, &rt) == -1)
perror("setrlimit");
printf("设置系统资源参数成功!/n");
/* 开启 socket 监听 */
if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1)
perror("socket");
printf("socket 创建成功!/n");
setnonblocking(listener);
bzero(&my_addr, sizeof(my_addr));
my_addr.sin_family = PF_INET;
my_addr.sin_port = htons(myport);
my_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(listener, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1)
perror("bind");
printf("IP 地址和端口绑定成功/n");
if (listen(listener, lisnum) == -1)
perror("listen");
printf("开启服务成功!/n");
/* 创建 epoll 句柄,把监听 socket 加入到 epoll 集合里 */
kdpfd = epoll_create(MAXEPOLLSIZE);
len = sizeof(struct sockaddr_in);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd =
if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listener, &ev) & 0)
fprintf(stderr, "epoll set insertion error: fd=%d/n", listener);
return -1;
printf("监听 socket 加入 epoll 成功!/n");
curfds = 1;
/* 等待有事件发生 */
nfds = epoll_wait(kdpfd, events, curfds, -1);
if (nfds == -1)
perror("epoll_wait");
/* 处理所有事件 */
for (n = 0; n & ++n)
if (events.data.fd == listener)
new_fd = accept(listener, (struct sockaddr *) &their_addr,&len);
if (new_fd & 0)
perror("accept");
printf("有连接来自于: %d:%d, 分配的 socket 为:%d/n",
inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port), new_fd);
setnonblocking(new_fd);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = new_
if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, new_fd, &ev) & 0)
fprintf(stderr, "把 socket '%d' 加入 epoll 失败!%s/n",
new_fd, strerror(errno));
return -1;
ret = handle_message(events.data.fd);
if (ret & 1 && errno != 11)
epoll_ctl(kdpfd, EPOLL_CTL_DEL, events.data.fd,&ev);
close(listener);
epoll_wait运行的原理是 等侍注册在epfd上的socket fd的事件的发生,如果发生则将发生的sokct fd和事件类型放入到events数组中。 并且将注册在epfd上的socket fd的事件类型给清空,所以如果下一个循环你还要关注这个socket fd的话,则需要用epoll_ctl(epfd,EPOLL_CTL_MOD,listenfd,&ev)来重新设置socket fd的事件类型。这时不用EPOLL_CTL_ADD,因为socket fd并未清空,只是事件类型清空。这一步非常重要。
二、第二个示例:
1. Epoll是何方神圣?
Epoll可是当前在Linux下开发大规模并发网络程序的热门人选,Epoll 在Linux2.6内核中正式引入,和select相似,其实都I/O多路复用技术而已,并没有什么神秘的。
其实在Linux下设计并发网络程序,向来不缺少方法,比如典型的Apache模型(Process Per Connection,简称PPC),TPC(Thread PerConnection)模型,以及select模型和poll模型,那为何还要再引入Epoll这个东东呢?那还是有得说说的…
2. 常用模型的缺点
如果不摆出来其他模型的缺点,怎么能对比出Epoll的优点呢。
2.1 PPC/TPC模型
这两种模型思想类似,就是让每一个到来的连接一边自己做事去,别再来烦我。只是PPC是为它开了一个进程,而TPC开了一个线程。可是别烦我是有代价的,它要时间和空间啊,连接多了之后,那么多的进程/线程切换,这开销就上来了;因此这类模型能接受的最大连接数都不会高,一般在几百个左右。
2.2 select模型
1. 最大并发数限制,因为一个进程所打开的FD(文件描述符)是有限制的,由FD_SETSIZE设置,默认值是,因此Select模型的最大并发数就被相应限制了。自己改改这个FD_SETSIZE?想法虽好,可是先看看下面吧…
2. 效率问题,select每次调用都会线性扫描全部的FD集合,这样效率就会呈现线性下降,把FD_SETSIZE改大的后果就是,大家都慢慢来,什么?都超时了??!!
3. 内核/用户空间 内存拷贝问题,如何让内核把FD消息通知给用户空间呢?在这个问题上select采取了内存拷贝方法。
2.3 poll模型
基本上效率和select是相同的,select缺点的2和3它都没有改掉。
3. Epoll的提升
把其他模型逐个批判了一下,再来看看Epoll的改进之处吧,其实把select的缺点反过来那就是Epoll的优点了。
3.1. Epoll没有最大并发连接的限制,上限是最大可以打开文件的数目,这个数字一般远大于2048, 一般来说这个数目和系统内存关系很大,具体数目可以cat /proc/sys/fs/file-max察看。
3.2. 效率提升,Epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll。
3.3. 内存拷贝,Epoll在这点上使用了“共享内存”,这个内存拷贝也省略了。
4. Epoll为什么高效
Epoll的高效和其数据结构的设计是密不可分的,这个下面就会提到。
首先回忆一下select模型,当有I/O事件到来时,select通知应用程序有事件到了快去处理,而应用程序必须轮询所有的FD集合,测试每个FD是否有事件发生,并处理事件;代码像下面这样:
int res = select(maxfd+1, &readfds, NULL, NULL, 120);
if(res & 0)
for(int i = 0; i & MAX_CONNECTION; i++)
if(FD_ISSET(allConnection[i],&readfds))
handleEvent(allConnection[i]);
// if(res == 0) handle timeout, res & 0 handle error
Epoll不仅会告诉应用程序有I/0事件到来,还会告诉应用程序相关的信息,这些信息是应用程序填充的,因此根据这些信息应用程序就能直接定位到事件,而不必遍历整个FD集合。
intres = epoll_wait(epfd, events, 20, 120);
for(int i = 0; i &i++)
handleEvent(events);
5. Epoll关键数据结构
前面提到Epoll速度快和其数据结构密不可分,其关键数据结构就是:
structepoll_event {
// Epoll events
epoll_data_
// User datavariable
typedef union epoll_data {
__uint32_t u32;
__uint64_t u64;
} epoll_data_t;
可见epoll_data是一个union结构体,借助于它应用程序可以保存很多类型的信息:fd、指针等等。有了它,应用程序就可以直接定位目标了。
6. 使用Epoll
既然Epoll相比select这么好,那么用起来如何呢?会不会很繁琐啊…先看看下面的三个函数吧,就知道Epoll的易用了。
intepoll_create(int size);
生成一个Epoll专用的文件描述符,其实是申请一个内核空间,用来存放你想关注的socket fd上是否发生以及发生了什么事件。size就是你在这个Epoll fd上能关注的最大socket fd数,大小自定,只要内存足够。
intepoll_ctl(int epfd, intop, int fd, structepoll_event *event);
控制某个Epoll文件描述符上的事件:注册、修改、删除。其中参数epfd是epoll_create()创建Epoll专用的文件描述符。相对于select模型中的FD_SET和FD_CLR宏。
intepoll_wait(int epfd,structepoll_event * events,int maxevents,int timeout);
等待I/O事件的发生;参数说明:
epfd:由epoll_create() 生成的Epoll专用的文件描述符;
epoll_event:用于回传代处理事件的数组;
maxevents:每次能处理的事件数;
timeout:等待I/O事件发生的超时值;
返回发生事件数。
相对于select模型中的select函数。
7. 例子程序
下面是一个简单Echo Server的例子程序,麻雀虽小,五脏俱全,还包含了一个简单的超时检查机制,简洁起见没有做错误处理。
// a simple echo server using epoll in linux
// :修改了几个问题,1是/n格式问题,2是去掉了原代码不小心加上的ET模式;
// 本来只是简单的示意程序,决定还是加上 recv/send时的buffer偏移
// by sparkling
#include &sys/socket.h&
#include &sys/epoll.h&
#include &netinet/in.h&
#include &arpa/inet.h&
#include &fcntl.h&
#include &unistd.h&
#include &stdio.h&
#include &errno.h&
#include &iostream&
#define MAX_EVENTS 500
struct myevent_s
void (*call_back)(int fd, int events, void *arg);
// 1: in epoll wait list, 0 not in
char buff[128]; // recv data buffer
int len, s_
long last_ // last active time
// set event
void EventSet(myevent_s *ev, int fd, void (*call_back)(int, int, void*), void *arg)
ev-&call_back = call_
ev-&events = 0;
ev-&status = 0;
bzero(ev-&buff, sizeof(ev-&buff));
ev-&s_offset = 0;
ev-&len = 0;
ev-&last_active = time(NULL);
// add/mod an event to epoll
void EventAdd(int epollFd, int events, myevent_s *ev)
struct epoll_event epv = {0, {0}};
epv.data.ptr =
epv.events = ev-&events =
if(ev-&status == 1){
op = EPOLL_CTL_MOD;
op = EPOLL_CTL_ADD;
ev-&status = 1;
if(epoll_ctl(epollFd, op, ev-&fd, &epv) & 0)
printf("Event Add failed[fd=%d], evnets[%d]\n", ev-&fd, events);
printf("Event Add OK[fd=%d], op=%d, evnets[%0X]\n", ev-&fd, op, events);
// delete an event from epoll
void EventDel(int epollFd, myevent_s *ev)
struct epoll_event epv = {0, {0}};
if(ev-&status != 1)
epv.data.ptr =
ev-&status = 0;
epoll_ctl(epollFd, EPOLL_CTL_DEL, ev-&fd, &epv);
int g_epollFd;
myevent_s g_Events[MAX_EVENTS+1]; // g_Events[MAX_EVENTS] is used by listen fd
void RecvData(int fd, int events, void *arg);
void SendData(int fd, int events, void *arg);
// accept new connections from clients
void AcceptConn(int fd, int events, void *arg)
struct sockaddr_
socklen_t len = sizeof(struct sockaddr_in);
if((nfd = accept(fd, (struct sockaddr*)&sin, &len)) == -1)
if(errno != EAGAIN && errno != EINTR)
printf("%s: accept, %d", __func__, errno);
for(i = 0; i & MAX_EVENTS; i++)
if(g_Events[i].status == 0)
if(i == MAX_EVENTS)
printf("%s:max connection limit[%d].", __func__, MAX_EVENTS);
// set nonblocking
int iret = 0;
if((iret = fcntl(nfd, F_SETFL, O_NONBLOCK)) & 0)
printf("%s: fcntl nonblocking failed:%d", __func__, iret);
// add a read event for receive data
EventSet(&g_Events[i], nfd, RecvData, &g_Events[i]);
EventAdd(g_epollFd, EPOLLIN, &g_Events[i]);
}while(0);
printf("new conn[%s:%d][time:%d], pos[%d]\n", inet_ntoa(sin.sin_addr),
ntohs(sin.sin_port), g_Events[i].last_active, i);
// receive data
void RecvData(int fd, int events, void *arg)
struct myevent_s *ev = (struct myevent_s*)
// receive data
len = recv(fd, ev-&buff+ev-&len, sizeof(ev-&buff)-1-ev-&len, 0);
EventDel(g_epollFd, ev);
if(len & 0)
ev-&len +=
ev-&buff[len] = '\0';
printf("C[%d]:%s\n", fd, ev-&buff);
// change to send event
EventSet(ev, fd, SendData, ev);
EventAdd(g_epollFd, EPOLLOUT, ev);
else if(len == 0)
close(ev-&fd);
printf("[fd=%d] pos[%d], closed gracefully.\n", fd, ev-g_Events);
close(ev-&fd);
printf("recv[fd=%d] error[%d]:%s\n", fd, errno, strerror(errno));
// send data
void SendData(int fd, int events, void *arg)
struct myevent_s *ev = (struct myevent_s*)
// send data
len = send(fd, ev-&buff + ev-&s_offset, ev-&len - ev-&s_offset, 0);
if(len & 0)
printf("send[fd=%d], [%d&-&%d]%s\n", fd, len, ev-&len, ev-&buff);
ev-&s_offset +=
if(ev-&s_offset == ev-&len)
// change to receive event
EventDel(g_epollFd, ev);
EventSet(ev, fd, RecvData, ev);
EventAdd(g_epollFd, EPOLLIN, ev);
close(ev-&fd);
EventDel(g_epollFd, ev);
printf("send[fd=%d] error[%d]\n", fd, errno);
void InitListenSocket(int epollFd, short port)
int listenFd = socket(AF_INET, SOCK_STREAM, 0);
fcntl(listenFd, F_SETFL, O_NONBLOCK); // set non-blocking
printf("server listen fd=%d\n", listenFd);
EventSet(&g_Events[MAX_EVENTS], listenFd, AcceptConn, &g_Events[MAX_EVENTS]);
// add listen socket
EventAdd(epollFd, EPOLLIN, &g_Events[MAX_EVENTS]);
// bind & listen
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(port);
bind(listenFd, (const sockaddr*)&sin, sizeof(sin));
listen(listenFd, 5);
int main(int argc, char **argv)
unsigned short port = 12345; // default port
if(argc == 2){
port = atoi(argv[1]);
// create epoll
g_epollFd = epoll_create(MAX_EVENTS);
if(g_epollFd &= 0) printf("create epoll failed.%d\n", g_epollFd);
// create & bind listen socket, and add to epoll, set non-blocking
InitListenSocket(g_epollFd, port);
// event loop
struct epoll_event events[MAX_EVENTS];
printf("server running:port[%d]\n", port);
int checkPos = 0;
// a simple timeout check here, every time 100, better to use a mini-heap, and add timer event
long now = time(NULL);
for(int i = 0; i & 100; i++, checkPos++) // doesn't check listen fd
if(checkPos == MAX_EVENTS) checkPos = 0; // recycle
if(g_Events[checkPos].status != 1)
long duration = now - g_Events[checkPos].last_
if(duration &= 60) // 60s timeout
close(g_Events[checkPos].fd);
printf("[fd=%d] timeout[%d--%d].\n", g_Events[checkPos].fd, g_Events[checkPos].last_active, now);
EventDel(g_epollFd, &g_Events[checkPos]);
// wait for events to happen
int fds = epoll_wait(g_epollFd, events, MAX_EVENTS, 1000);
if(fds & 0){
printf("epoll_wait error, exit\n");
for(int i = 0; i & i++){
myevent_s *ev = (struct myevent_s*)events[i].data.
if((events[i].events&EPOLLIN)&&(ev-&events&EPOLLIN)) // read event
ev-&call_back(ev-&fd, events[i].events, ev-&arg);
if((events[i].events&EPOLLOUT)&&(ev-&events&EPOLLOUT)) // write event
ev-&call_back(ev-&fd, events[i].events, ev-&arg);
// free resource
如果您想留下此文,您可以将其发送至您的邮箱(将同时以邮件内容&PDF形式发送)
相关文章推荐
(Ctrl+Enter提交) &&
已有0人在此发表见解
&在& 23:13收藏到了
&&在信息爆炸的时代,您的知识需要整理,沉淀,积累!Lai18为您提供一个简单实用的文章整理收藏工具,在这里您可以收藏对您有用的技术文章,自由分门别类,在整理的过程中,用心梳理自己的知识!相信,用不了多久,您收藏整理的文章将是您一生的知识宝库!
· 蜀ICP备号-1

我要回帖

更多关于 libevent2 的文章

 

随机推荐