Libevent官方代码样例学习(二)
连接监听器: 接收TCP连接请求
evconnlistener机制用于监听并接受TCP连接请求. 这些方法在event2/listener.h中声明, 在Libevent 2.0.2-alpha之后的版本中可用.
创建和释放evconnlistener
struct evconnlistener *evconnlistener_new( struct event_base *base, evconnlistener_cb cb, void *ptr, unsigned flags, int backlog, evutil_socket_t fd);
struct evconnlistener *evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb, void *ptr, unsigned flags, int backlog, const struct sockaddr *sa, int socklen);
void evconnlistener_free(struct evconnlistener *lev);
这两个 evconnlistener_new*() 方法都会allocate并返回一个新的connection listener对象. connection listener使用event_base 来通知来自于制定的socket上的新的TCP连接请求. 并调用预设的回调方法.
这两个方法相同的参数:
base 是listener用来监听的event_base.
cb 是回调方法, 如果cb is NULL, listener会被视为禁用, 直到回调被设置.
ptr 指针会作为参数被传递给回调方法.
flags 参数控制listener的行为.
backlog 参数控制允许的等待的连接数的上限. 如果backlog是负数, Libevent会自动设置一个合适的值, 如果为0, 则Libevent会认为你已经在socket上调用了listen()方法.
这两个方法中不同的参数, 在于如何初始化listener socket. evconnlistener_new() 方法假定你已经在要监听的端口上绑定了socket, 你只需要传递socket的fd就够. 如果你希望Libevent自己allocate并绑定socket, 就调用evconnlistener_new_bind(), 并传入你想监听的的sockaddr和它的length.
|
Tip
|
[使用 evconnlistener_new时要确保监听的socket工作于non-blocking 状态, (用evutil_make_socket_nonblocking 或手工指定正确的socket选项). When the listening socket is left in blocking mode, undefined behavior might occur.] |
要释放一个 listener, 使用evconnlistener_free().
创建一个signal events
Libevent can also watch for POSIX-style signals. 要创建一个signal的handler, 使用接口:
#define evsignal_new(base, signum, cb, arg) event_new(base, signum, EV_SIGNAL|EV_PERSIST, cb, arg)
可以看到其实是调用了event_new, 只不过flag是EV_SIGNAL|EV_PERSIST, 并且不是传fd而是传signum
struct event *hup_event;
struct event_base *base = event_base_new(); /* call sighup_function on a HUP signal */
hup_event = evsignal_new(base, SIGHUP, sighup_function, NULL);
注意: signal回调在signal发生后, 在event loop中执行, 所以一些在常规POSIX信号handler中不能调用的方法是可以在这种情况下调用的.
|
注意
|
不要在signal event中设置timeout |
另外一些相关的宏设定:
#define evsignal_add(ev, tv) \
event_add((ev),(tv))
#define evsignal_del(ev) \
event_del(ev)
#define evsignal_pending(ev, what, tv_out) \
event_pending((ev), (what), (tv_out))
evsignal_* 宏定义也是在Libevent 2.0.1-alpha之后的版本中可用.
例子
/*
This example program provides a trivial server program that listens for TCP
connections on port 9995. When they arrive, it writes a short message to
each client connection, and closes each connection once it is flushed.
Where possible, it exits cleanly in response to a SIGINT (ctrl-c).
*/
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h> static const char MESSAGE[] = "Hello, World!\n";
static const int PORT = ;
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 *); int
main(int argc, char **argv) {
struct event_base *base;
struct evconnlistener *listener;
struct event *signal_event;
struct sockaddr_in sin; base = event_base_new();
if (!base) {
fprintf(stderr, "Could not initialize libevent!\n");
return ;
} memset(&sin, , sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
listener = evconnlistener_new_bind(
base, listener_cb, (void *) base, LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, -,
(struct sockaddr *) &sin, sizeof(sin)); if (!listener) {
fprintf(stderr, "Could not create a listener!\n");
return ;
} signal_event = evsignal_new(base, SIGINT, signal_cb, (void *) base); if (!signal_event || event_add(signal_event, NULL) < ) {
fprintf(stderr, "Could not create/add a signal event!\n");
return ;
} event_base_dispatch(base);
evconnlistener_free(listener);
event_free(signal_event);
event_base_free(base);
printf("done\n");
return ;
} 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; bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
if (!bev) {
fprintf(stderr, "Error constructing bufferevent!");
event_base_loopbreak(base);
return;
}
bufferevent_setcb(bev, NULL, conn_writecb, conn_eventcb, NULL);
bufferevent_enable(bev, EV_WRITE);
bufferevent_disable(bev, EV_READ);
bufferevent_write(bev, MESSAGE, strlen(MESSAGE));
} 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);
}
} static void
conn_eventcb(struct bufferevent *bev, short events, void *user_data) {
if (events & BEV_EVENT_EOF) {
printf("Connection closed.\n");
} else if (events & BEV_EVENT_ERROR) {
printf("Got an error on the connection: %s\n", strerror(errno));/*XXX win32*/
}
/* None of the other events can happen here, since we haven't enabled
* timeouts */
bufferevent_free(bev);
} 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官方代码样例学习(二)的更多相关文章
- Libevent官方代码样例学习(一)
在Ubuntu16.04中, libevent的默认安装位置为 #在 trusty 发行版中 amd64 硬件架构下的 libevent- 软件包文件清单 /usr/lib/x86_64-linux- ...
- scrapy爬虫学习系列二:scrapy简单爬虫样例学习
系列文章列表: scrapy爬虫学习系列一:scrapy爬虫环境的准备: http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_python_00 ...
- 33个超级有用必须要收藏的PHP代码样例
作为一个正常的程序员,会好几种语言是十分正常的,相信大部分程序员也都会编写几句PHP程序,如果是WEB程序员,PHP一定是必备的,即使你没用开发过大型软件项目,也一定多少了解它的语法. 在PHP的流行 ...
- java servlet 代码样例 (demo)
今天又搞了下jsp +servlet 的代码样例,感觉虽然搭了好多次,可是每次还是不记得那些参数,都要去网上搜索,索性自己把这次的简单demo给记录下来,供下次使用的时候直接复制吧. 这个web逻辑 ...
- 模式识别 - 处理多演示样例学习(MIL)特征(matlab)
处理多演示样例学习(MIL)特征(matlab) 本文地址: http://blog.csdn.net/caroline_wendy/article/details/27206325 多演示样例学习( ...
- 2020JAVA最新应对各种OOM代码样例及解决办法
引言 作者:黄青石 链接:https://www.cnblogs.com/huangqingshi/p/13336648.html?utm_source=tuicool&utm_medium= ...
- zookeeper实战:SingleWorker代码样例
我们需要一个“单点worker”系统,此系统来确保系统中定时任务在分布式环境中,任意时刻只有一个实例处于活跃:比如,生产环境中,有6台机器支撑一个应用,但是一个应用中有30个定时任务,这些任务有些必须 ...
- 30个php操作redis经常用法代码样例
这篇文章主要介绍了30个php操作redis经常用法代码样例,本文事实上不止30个方法,能够操作string类型.list类型和set类型的数据,须要的朋友能够參考下 redis的操作非常多的,曾经看 ...
- JAVA各种OOM代码样例及解决方法
周末了,觉得我还有很多作业没有写,针对目前大家对OOM的类型不太熟悉,那么我们来总结一下各种OOM出现的情况以及解决方法. 我们把各种OOM的情况列出来,然后逐一进行代码编写复现和提供解决方法. 1. ...
随机推荐
- ARouter 路由 组件 跳转 MD
目录 简介 支持的功能 典型应用 简单使用 进阶使用 更多功能 其他 Q&A Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs bai ...
- jquery ajax 的 $.get()用法详解
js文件 $(document).ready(function(){ $("form").submit(function(event) {event.preventDefault( ...
- ODBC更新记录集提示”记录集为只读“
创建的ODBC应用程序默认的记录集不具有只读属性,但是再更新记录表时会提示”记录集为只读“,这是为什么呢? 今天看书找到了答案: 因为MFC中的数据库类不支持需要连接两个或者多个表的记录集更新,如果选 ...
- NLP--自然语言处理与机器学习会议
http://blog.csdn.net/ice110956/article/details/17090061 整理至11月中旬在重庆参加的自然语言处理与机器学习会议,第一讲为自然语言处理. 由基本理 ...
- uboot mmc read/write命令用法
mmc read用来读取mmc内容到内存, mmc write用来写入内存内容到mmc中 具体用法, mmc read <device num> addr blk# cnt [partit ...
- Windows平台下使用Beyond Compare作为GIT默认的比对与合并工具
在Windows平台使用GUI习惯了,因此在CMD命令下反而感到不适 特别是在使用GIT时,尤其明显(这主要是GIT在工作中已经不可或缺) 使用GIT最常用的功能就是提交,添加,比较差异和合并分支,特 ...
- 转: Centos安装gcc及g++
Centos安装gcc及g++ Centos支持yum安装,安装软件一般格式为yum install .......,注意安装时要先成为root用户. 按照这个思路,我想安装过程如下: 安装gcc ...
- 数据库迁移工具Navicat Premium之OracleToMysql
一.问题 由于工作需要,需要把业务库的数据库从oracle签到mysql,免费开源 二.解决办法 2.1:ETL单个对象进行转移(最笨的办法,所以抛弃掉了) 2.2:使用Navicat Premium ...
- Excel长数字防止转换为科学计数法
网上的一个方法是,加单引号,但是不好看. 我的处理,是先加,再替换成带格式的. strTable = Formater.SimpleTable(dt, "aaa", "| ...
- OpenGL ES 3.0之Fragment buffer objects(FBO)详解(一)
片段操作图 这篇文章将介绍从写入帧缓冲和读取帧缓冲的方式. Buffers(缓冲) OpenGL ES支持三种缓冲: OpenGL ES •• Color buffer颜色缓冲 •• Depth bu ...