libevent学习之网络通信
服务器端
要实现网络通信,肯定会用到socket等函数,这几个函数应该没什么问题。libevent默认情况下是单线程的,可以配置成多线程,每个线程有一个event_base,对应一个struct event _base结构体以及一个事件管理器,调度托管给它的一系列事件。所以当一个事件发生后,先创建一个event_base,再创建一个事件,将这个事件绑定,然后添加到event_base中,启动event_base的循环,开始处理事件。大概流程如下:
1 参数解析;
2. 创建socket连接;
3. struct event_base *base = event_base_new();创建一个event_base;
event_base_new()函数分配并且返回一个新的具有默认设置的 event_base。函数会检测环境变量,返回一个到 event_base 的指针。如果发生错误,则返回 NULL。选择各种方法时,函数会选择 OS 支持的最快方法。
4struct event* listen_event;创建一个监听事件;
5event_new(base,listenfd,EV_READ | EV_PERSIST,accept_cb,base);使用event_new()函数将监听事件绑定;
参数:event_base监听的对象,需要监听的事件,事件发生后的回调函数,传给回调函数的参数。libevent支持的事件及属性包括(使用bitfield实现)
EV_TIMEOUT:超时;
EV_READ:只要网络缓冲中还有数据,回调函数就会被触发;
EV_WRITE:只要塞给网络缓冲的数据被写完,回调函数就会被触发;
EV_SIGNAL:POSIX信号量;
EV_PERSIST:不指定这个属性,回调函数被触发后事件会被删除;
EV_ET:Edge-Trigger边缘触发
6event_add(listen_event,NULL);将监听事件绑定到event_base中;
7event_base_dispatch(base);启动循环开始处理事件;
8事件发生时的回调函数typedef void(* event_callback_fn)(evutil_socket_t sockfd, short event_type, void *arg)
传给callback_func的是一个监听的事件类型fd,以及event_new中最后一个参数。
如下是代码:
int main(int argc,char **argv)
{
int listenfd;
int ch;
int port;
struct option opt[]={
{"port",required_argument,NULL,'p'},
{"help",no_argument,NULL,'h'},
{NULL,0,NULL,0}
};
while( (ch=getopt_long(argc,argv,"p:h",opt,NULL))!=-1 )
{
switch(ch)
{
case 'p':
port=atoi(optarg);
break;
case 'h':
print_help(argv[0]);
return 0;
}
}
printf("port:%d\n",port);
if( !port )
{
print_help(argv[0]);
return 0;
}
listenfd=socket_init(NULL,port);
if( listenfd<0 )
{
printf("socket_init failure!\n");
return -1;
}
printf("socket_init successfully!\n");
/*创建一个event_base*/
struct event_base *base = event_base_new();
assert(base != NULL);//设置event_base不为空
/*创建并绑定一个event*/
struct event* listen_event;
listen_event=event_new(base,listenfd,EV_READ | EV_PERSIST,accept_cb,base);
/*添加监听事件*/
event_add(listen_event,NULL);
/*启动循环,开始处理事件*/
event_base_dispatch(base);
return 0;
}
/*回调函数accept_cb*/
void accept_cb(int fd, short events, void* arg)
{
struct sockaddr_in cliaddr;
evutil_socket_t clifd;
socklen_t len=sizeof(cliaddr);
clifd=accept(fd,(struct sockaddr*)&cliaddr,&len);
if( clifd<0 )
{
printf("accept client %d failure!\n",clifd);
close(clifd);
}
evutil_make_socket_nonblocking(clifd);//设置为非阻塞模式
printf("accept client %d successfully!\n",clifd);
struct event_base* base = (struct event_base*)arg;
/*动态创建一个event结构体,并将其作为回调参数传递给*/
struct event* cli_event = event_new(NULL, -1, 0, NULL, NULL);
event_assign(cli_event,base, clifd, EV_READ | EV_PERSIST,read_cb, (void*)cli_event);
event_add(cli_event,NULL);
}
/*accept的回调函数read_cb*/
void read_cb(int fd, short events, void* arg)
{
int rv;
char buf[1024];
struct event* ev = (struct event*)arg;
rv=read(fd,buf,sizeof(buf));
if( rv<=0 )
{
printf("read message failure!\n");
event_free(ev);
close(fd);
return ;
}
printf("read message successfully:%s\n",buf);
char reply_buf[1024] = "I have received the msg: ";
strcat(reply_buf + strlen(reply_buf), buf);
write(fd,reply_buf,sizeof(reply_buf));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
客户端
客户端的实现与服务器端基本相似,先实现socket的连接,然后创建event_base,创建并绑定监听事件,添加监听事件,启动循环,开始处理事件。代码如下:
int main(int argc, char** argv)
{
int ch;
int sockfd;
char *server_ip=NULL;
int server_port=0;
struct option opt[]={
{"server_ip",required_argument,NULL,'i'},
{"server_port",required_argument,NULL,'p'},
{"help",no_argument,NULL,'h'},
{NULL,0,NULL,0}
};
while( (ch=getopt_long(argc,argv,"i:p:h",opt,NULL))!=-1 )
{
switch(ch)
{
case 'i':
server_ip=optarg;
break;
case 'p':
server_port=atoi(optarg);
break;
case 'h':
print_help(argv[0]);
return 0;
}
}
if(!server_port)
{
print_help(argv[0]);
return 0;
}
sockfd=socket_connect(server_ip,server_port);
if( sockfd<0 )
{
printf("connect to server failure!\n");
return -1;
}
printf("connect to server successfully!\n");
struct event_base* base = event_base_new();
struct event *sockevent = event_new(base, sockfd, EV_READ | EV_PERSIST, read_cb, NULL);
event_add(sockevent, NULL);
//监听终端输入事件
struct event* ev_input = event_new(base, STDIN_FILENO, EV_READ | EV_PERSIST, input_cb, (void*)&sockfd);
event_add(ev_input, NULL);
event_base_dispatch(base);
printf("finished \n");
return 0;
}
/*读回调函数*/
void read_cb(int fd, short events, void *arg)
{
char buf[1024];
int rv;
rv=read(fd,buf,sizeof(buf));
if( rv<=0 )
{
printf("read data from server %dfailure!\n",fd);
exit(1);
}
printf("read %d data from server:%s\n",rv,buf);
}
/*输入信息回调函数*/
void input_cb(int fd, short events, void* arg)
{
char buf[1024];
int rv;
rv=read(fd,buf,sizeof(buf));
if( rv<=0 )
{
printf("read failure!\n");
exit(1);
}
//把终端的消息发送给服务器端
int sockfd = *((int*)arg);
write(sockfd,buf,rv);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
下面是运行结果:
客户端:
服务器端:
---------------------
libevent学习之网络通信的更多相关文章
- libevent学习之二:Windows7(Win7)下编译libevent
Linux下编译参考源码中的README文件即可,这里主要记录Windows下的编译. 一.准备工作 去官网下载最新的稳定发布版本libevent-2.0.22-stable 官网地址:http:// ...
- 【传智播客】Libevent学习笔记(一):简介和安装
目录 00. 目录 01. libevent简介 02. Libevent的好处 03. Libevent的安装和测试 04. Libevent成功案例 00. 目录 @ 01. libevent简介 ...
- PHP中的Libevent学习
wangbin@2012,1,3 目录 Libevent在php中的应用学习 1. Libevent介绍 2. 为什么要学习libevent 3. Php libeven ...
- libevent学习笔记 一、基础知识【转】
转自:https://blog.csdn.net/majianfei1023/article/details/46485705 欢迎转载,转载请注明原文地址:http://blog.csdn.net/ ...
- Libevent学习之SocketPair实现
Libevent设计的精化之一在于把Timer事件.Signal事件和IO事件统一集成在一个Reactor中,以统一的方式去处理这三种不同的事件,更确切的说是把Timer事件和Signal事件融合到了 ...
- libevent学习笔记 —— 牛刀小试:简易的服务器
回想起之前自己用纯c手动写epoll循环,libevent用起来还真是很快捷啊!重写了之前学习的时候的一个例子,分别用纯c与libevent来实现.嗯,为了方便对比一下,就一个文件写到黑了. 纯c版: ...
- Libevent学习笔记(五) 根据例子学习bufferevent
libevent中提供了一个Hello-world.c 的例子,从这个例子可以学习libevent是如何使用bufferevent的. 这个例子在Sample中 这个例子之前讲解过,这次主要看下buf ...
- libevent学习文档(三)working with event
Events have similar lifecycles. Once you call a Libevent function to set up an event and associate i ...
- Libevent 学习笔记 (1)——Libevent 2.0安装与简单演示样例
今天開始学习Libevent . Libevent 是开源社区的一款高性能I/O框架库. 主要特点有: 1 跨平台. 2 统一事件源 3 线程安全 4 基于Reactor 今天主要进行了Libeven ...
随机推荐
- Dynamics CRM 修改Excel 最大导出记录限制及 最大上传文件限制
CRM默认的Excel最大导出记录是10000条,最大上传文件限制为5m. 这样的限制可以满足少量数据的批量更新,但是如果数据量比较大的话需要修改最大的导出记录限制,和上传文件的大小,网上有的是直接修 ...
- 修改phpmyadmin中的默认超时时间
phpmyadmin在使用过程中经常出现"登陆超时(1440秒未活动),请重新登录",很烦 解决方法如下: 第一步: 修改php.ini,找到 session.gc_maxlife ...
- 并不对劲的noip2018
day1 road 题意 有n(\(n \leq 10^5\))个数\(a_1,a_2,...,a_n\)排成一排,每次可以选择一段大于零的数减一,问最少几次把所有数减为0. 题解 先想到一个简单的策 ...
- bzoj 4543 HOTEL 加强版
题目大意: 求树上取三个点这三个点两两距离相等的方案数 思路: 远古时候的$n^2$做法是换根 但那样无法继续优化了 学习了一波长链剖分 考虑如何在一棵树上进行dp 设$f[i][j]$表示以$i$为 ...
- 【HAOI 2015】 树上操作
[题目链接] 点击打开链接 [算法] 树链剖分 子树的DFS序是连续的一段! [代码] #include<bits/stdc++.h> using namespace std; #defi ...
- 反编译Android的apk包得到源码(使用工具:dex2jar和jd-gui)
1. 先从 http://download.csdn.net/detail/dingyuming1991/9618125 下载反编译工具dex2jar和jd-gui(当然也可以google搜索下载): ...
- 金融事业部QA培训体系
此文已由作者夏君授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 引言 总结2015,放眼2016,纵观整个互联网圈,人才依然是业务成功的第一要素,在网易,我想也是这样 ...
- Ceph之对象存储网关RADOS Gateway(RGW)
一.Ceph整体架构及RGW在Ceph中的位置 1.Ceph的整体架构 Ceph是一个统一的.分布式的的存储系统,具有优秀的性能.可靠性和可扩展性.Ceph支持对象存储(RADOSGW).块存储(RB ...
- 洛谷P2607 [ZJOI2008]骑士(基环树)
传送门 首先这是一个有$n$个点$n$条边的图(据大佬们说这玩意儿叫做基环树?) 不难(完全没有)发现每个连通块里最多只有一个环 那么找到这个环,然后把它断开,再对它的两个端点分别跑树形dp 设$dp ...
- mac下安装ngnix以及开启关闭重启
一.安装 执行如下命令 brew search nginx brew install nginx 安装完以后,可以在终端输出的信息里看到一些配置路径: /usr/local/etc/nginx/ngi ...