示例的libevent的程序
著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
作者:auxten
链接:http://zhuanlan.zhihu.com/auxten/20315482
来源:知乎 /*
这是一个示例性质的libevent的程序,监听在TCP的9995端口。
当连接建立成功后,它将会给Client回应一个消息"Hello, World!\n"
发送完毕后就将连接关闭。 程序也处理了SIGINT (ctrl-c)信号,收到这个信号后优雅退出程序。 这个程序也用到了一些libevent比较高级的API:“bufferevent”
这套API将buffer的“水位线”也抽象成了event来处理,灵感应该是来自
Windows平台的IOCP。
*/ // 引入常用Linux系统头文件
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h> // 引入libevent 2.x相关的头文件
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h> // 定义字符串常量,将会回应给Client用
static const char MESSAGE[] = "Hello, World!\n"; // server监听的端口
static const int PORT = ; // 定义几个event callback的prototype(原型)
static void listener_cb(struct evconnlistener * , evutil_socket_t,
struct sockaddr * , int socklen, void * );
static void conn_writecb(struct bufferevent * , void * );
static void conn_eventcb(struct bufferevent * , short, void * );
static void signal_cb(evutil_socket_t, short, void * ); // 定义标准的main函数
int
main(int argc, char ** argv)
{
// event_base是整个event循环必要的结构体
struct event_base * base;
// libevent的高级API专为监听的FD使用
struct evconnlistener * listener;
// 信号处理event指针
struct event * signal_event;
// 保存监听地址和端口的结构体
struct sockaddr_in sin; // 分配并初始化event_base
base = event_base_new();
if (!base) {
// 如果发生任何错误,向stderr(标准错误输出)打一条日志,退出
// 在C语言里,很多返回指针的API都以返回null为出错的返回值
// if (!base) 等价于 if (base == null)
fprintf(stderr, "Could not initialize libevent!\n");
return ;
} // 初始化sockaddr_in结构体,监听在0.0.0.0:9995
memset(&sin, , sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT); // bind在上面制定的IP和端口,同时初始化listen的事件循环和callback:listener_cb
// 并把listener的事件循环注册在event_base:base上
listener = evconnlistener_new_bind(base, listener_cb, (void * )base,
LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -,
(struct sockaddr*)&sin,
sizeof(sin)); if (!listener) {
// 如果发生任何错误,向stderr(标准错误输出)打一条日志,退出
fprintf(stderr, "Could not create a listener!\n");
return ;
} // 初始化信号处理event
signal_event = evsignal_new(base, SIGINT, signal_cb, (void * )base); // 把这个callback放入base中
if (!signal_event || event_add(signal_event, NULL)<) {
fprintf(stderr, "Could not create/add a signal event!\n");
return ;
} // 程序将在下面这一行内启动event循环,只有在调用event_base_loopexit后
// 才会从下面这个函数返回,并向下执行各种清理函数,导致整个程序退出
event_base_dispatch(base); // 各种清理free
evconnlistener_free(listener);
event_free(signal_event);
event_base_free(base); printf("done\n");
return ;
} // 监听端口的event callback
static void
listener_cb(struct evconnlistener * listener, evutil_socket_t fd,
struct sockaddr * sa, int socklen, void * user_data)
{
struct event_base * base = user_data;
struct bufferevent * bev; // 新建一个bufferevent,设定BEV_OPT_CLOSE_ON_FREE,
// 保证bufferevent被free的时候fd也会被关闭
bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
if (!bev) {
fprintf(stderr, "Error constructing bufferevent!");
event_base_loopbreak(base);
return;
}
// 设定写buffer的event和其它event
bufferevent_setcb(bev, NULL, conn_writecb, conn_eventcb, NULL);
// 开启向fd中写的event
bufferevent_enable(bev, EV_WRITE);
// 关闭从fd中读写入buffer的event
bufferevent_disable(bev, EV_READ);
// 向buffer中写入"Hello, World!\n"
// 上面的操作保证在fd可写时,将buffer中的内容写出去
bufferevent_write(bev, MESSAGE, strlen(MESSAGE));
} // 每次fd可写,数据非阻塞写入后,会雕也难怪conn_writecb
// 这个函数每次检查eventbuffer的剩余大小,如果为0
// 表示数据已经全部写完,将eventbuffer free掉
// 由于在上面设定了BEV_OPT_CLOSE_ON_FREE,所以fd也会被关闭
static void
conn_writecb(struct bufferevent * bev, void * user_data)
{
struct evbuffer * output = bufferevent_get_output(bev);
if (evbuffer_get_length(output) == ) {
printf("flushed answer\n");
bufferevent_free(bev);
}
} // 处理读、写event之外的event的callback
static void
conn_eventcb(struct bufferevent * bev, short events, void * user_data)
{
if (events & BEV_EVENT_EOF) {
// Client端关闭连接
printf("Connection closed.\n");
} else if (events & BEV_EVENT_ERROR) {
// 连接出错
printf("Got an error on the connection: %s\n",
strerror(errno));
}
// 如果还有其它的event没有处理,那就关闭这个bufferevent
bufferevent_free(bev);
} // 信号处理event,收到SIGINT (ctrl-c)信号后,延迟2s退出event循环
static void
signal_cb(evutil_socket_t sig, short events, void * user_data)
{
struct event_base * base = user_data;
struct timeval delay = { , }; printf("Caught an interrupt signal; exiting cleanly in two seconds.\n"); event_base_loopexit(base, &delay);
}
示例的libevent的程序的更多相关文章
- 分布式 PostgreSQL 集群(Citus)官方示例 - 多租户应用程序实战
如果您正在构建软件即服务 (SaaS) 应用程序,您可能已经在数据模型中内置了租赁的概念. 通常,大多数信息与租户/客户/帐户相关,并且数据库表捕获这种自然关系. 对于 SaaS 应用程序,每个租户的 ...
- 课程作业01:模仿JavaAppArguments.java示例,编写一个程序,此程序从命令行接收多个数字,求和之后输出结果。
1.设计思想: 首先是从JavaAppArguments.java示例开始,此示例已打印参数,定义数字 之和和作为存储单位的整型,然后将输入参数的字符串转化为整型,之后求和即可. 2.程序流程图: 3 ...
- 模仿JavaAppArguments.java示例,编写一个程序,此程序从命令行接收多个数 字,求和之后输出结果,写出其的设计思想、程序流程图、源程序代码。
一 设计思想 首先现在file中建立一个类,并把任务名和类名写上(注意类名的大写):第二步则是参数的输入,并且定义求和变量:第三步则是对参数数据类型的要求,要把字符类型转化为整数类型并输出(这也是本道 ...
- 用inno Setup做应用程序安装包的示例脚本(.iss文件)(
用innoSetup做应用程序安装包的示例脚本(.iss文件),具体要看innoSetup附带的文档,好象是pascal语言写的脚本. 示例1(应用程序.exe,客户端安装): ;{089D6802- ...
- 使用 libevent 和 libev 提高网络应用性能
使用 libevent 和 libev 提高网络应用性能 Martin C. Brown, 作家, Freelance 简介: 构建现代的服务器应用程序需要以某种方法同时接收数百.数千甚至数万个事件, ...
- libevent 和 libev 提高网络应用性能
构建现代的服务器应用程序需要以某种方法同时接收数百.数千甚至数万个事件,无论它们是内部请求还是网络连接,都要有效地处理它们的操作.有许多解决方 案,但是 libevent 库和 libev 库能够大大 ...
- 体验了微信小程序,发现安卓用户终于把果粉“碾压”了一次
今天早上,张小龙在微信公开课上分享了小程序的理念,并且公布了小程序将于1月9日上线. 为了体现张小龙对未来程序形态的理解,小程序有四个特定:无需安装.触手可及.用完即走.无需卸载.今天,36氪刚好有机 ...
- C++程序设计之四书五经[转自2004程序员杂志]--下篇
C++程序设计之四书五经(下篇) 作者:荣耀 我在上篇中“盘点”了TCPL和D&E以及入门教程.高效和健壮编程.模板和泛型编程等方面共十几本C++好书.冬去春来,让我们继续C++书籍精彩之旅. ...
- Spring MVC 入门示例讲解
在本例中,我们将使用Spring MVC框架构建一个入门级web应用程序.Spring MVC 是Spring框架最重要的的模块之一.它以强大的Spring IoC容器为基础,并充分利用容器的特性来简 ...
随机推荐
- cocos2dx-3.0(8)------Label、LabelTTF、LabelAtlas、LabelBMFont使用之法
----我的生活,我的点点滴滴!! 最后一个LabelBMFont了,字体图集LabelBMFont,LabelBMFont类是一个基于位图的字体图集.是一个包括全部你须要于坐标数据一起显示在屏幕上的 ...
- Spring学习十二----------Bean的配置之@ImportResource和@Value
© 版权声明:本文为博主原创文章,转载请注明出处 @ImportResource -引入XML配置文件 @Value -从配置文件中获取值 实例 1.项目结构 2.pom.xml <projec ...
- 怎样替换jar包的指定文件
在做(或修改别人的)项目的时候,可能遇到要修改调用的的jar包内的类属性或方法的问题.在eclipse或是其他的IDE中是无法直接修改的,所以需要一个解压jar-->修改文件-->编译-- ...
- java中BigDecimal的学习
干着java的活,但是看的都是一些偏底层的东西(或者我根本就没有看),有点荒废了java的学习. 最近一直在用到一个类是BigDecimal,但都是模棱两可地在那儿用,并没有深入研究这个类的细节,感觉 ...
- Linux 文件系统IO性能优化
对于LINUX SA来说,服务器性能是需要我们特别关注的,包括CPU.IO.内存等等系统的优化变得至关重要,这里转载一篇非常不错的关于IO优化的文章,供大家参考和学习: 一.关于页面缓存的信息,可以用 ...
- erlang动态生成随机key
取随机数,举个例子: 获取动态随机key值16位(key的范围是由"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678 ...
- 2015最流行的Android组件、工具、框架大全(转)
转自:2015最流行的Android组件.工具.框架大全 Android 是目前最流行的移动操作系统之一. 随着新版本的不断发布, Android的功能也日益强大, 涌现了很多流行的应用程序, 也催生 ...
- php生成唯一的串
1.方法一: <?php md5(uniqid('aa',true)); ?> 2.方法2: //生成16位的串$randLength=6; $chars='abcdefghijklmno ...
- ios-逆向 手把手安装最新版Theos
Theos.最初由DHowett进行开发,由于DHwoett去了微软,不再有时间维护了,所以Adam Demasi(kirb)接手了他的工作,并且添加了很多全新的功能.所以,之前书上<iOS ...
- 前端要给力之:语句在JavaScript中的值
文件夹 文件夹 问题是语句有值吗 那么说你骗我咯 有啥米用呢 研究这个是不是闲得那个啥疼 ES5ES6有什么差异呢 结论是ES6是改了规则但更合理 最后不不过if语句 这两天在写语言精髓那本书的第三版 ...