Libevent使用样例,从简单到复杂
转载请注明出处:http://blog.csdn.net/luotuo44/article/details/39670221
本文从简单到复杂。展示怎样使用libevent。网上的很多样例都是仅仅有server端的,本文里面client和server端都有,以飨读者。
关于libevent编程时的一些疑问能够阅读《libevent编程疑难解答》。假如读者还想了解libevent的详细实现,能够阅读《libevent源代码分析》系统文章。
不说这么多了。直接上代码。
初等:
client代码:
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<errno.h>
#include<unistd.h> #include<stdio.h>
#include<string.h>
#include<stdlib.h> #include<event.h>
#include<event2/util.h> int tcp_connect_server(const char* server_ip, int port); void cmd_msg_cb(int fd, short events, void* arg);
void socket_read_cb(int fd, short events, void *arg); int main(int argc, char** argv)
{
if( argc < 3 )
{
printf("please input 2 parameter\n");
return -1;
} //两个參数依次是服务器端的IP地址、端口号
int sockfd = tcp_connect_server(argv[1], atoi(argv[2]));
if( sockfd == -1)
{
perror("tcp_connect error ");
return -1;
} printf("connect to server successful\n"); struct event_base* base = event_base_new(); struct event *ev_sockfd = event_new(base, sockfd,
EV_READ | EV_PERSIST,
socket_read_cb, NULL);
event_add(ev_sockfd, NULL); //监听终端输入事件
struct event* ev_cmd = event_new(base, STDIN_FILENO,
EV_READ | EV_PERSIST, cmd_msg_cb,
(void*)&sockfd); event_add(ev_cmd, NULL); event_base_dispatch(base); printf("finished \n");
return 0;
} void cmd_msg_cb(int fd, short events, void* arg)
{
char msg[1024]; int ret = read(fd, msg, sizeof(msg));
if( ret <= 0 )
{
perror("read fail ");
exit(1);
} int sockfd = *((int*)arg); //把终端的消息发送给服务器端
//为了简单起见。不考虑写一半数据的情况
write(sockfd, msg, ret);
} void socket_read_cb(int fd, short events, void *arg)
{
char msg[1024]; //为了简单起见,不考虑读一半数据的情况
int len = read(fd, msg, sizeof(msg)-1);
if( len <= 0 )
{
perror("read fail ");
exit(1);
} msg[len] = '\0'; printf("recv %s from server\n", msg);
} typedef struct sockaddr SA;
int tcp_connect_server(const char* server_ip, int port)
{
int sockfd, status, save_errno;
struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr) ); server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
status = inet_aton(server_ip, &server_addr.sin_addr); if( status == 0 ) //the server_ip is not valid value
{
errno = EINVAL;
return -1;
} sockfd = ::socket(PF_INET, SOCK_STREAM, 0);
if( sockfd == -1 )
return sockfd; status = ::connect(sockfd, (SA*)&server_addr, sizeof(server_addr) ); if( status == -1 )
{
save_errno = errno;
::close(sockfd);
errno = save_errno; //the close may be error
return -1;
} evutil_make_socket_nonblocking(sockfd); return sockfd;
}
server端代码:
#include<stdio.h>
#include<string.h>
#include<errno.h> #include<unistd.h>
#include<event.h> void accept_cb(int fd, short events, void* arg);
void socket_read_cb(int fd, short events, void *arg); int tcp_server_init(int port, int listen_num); int main(int argc, char** argv)
{ int listener = tcp_server_init(9999, 10);
if( listener == -1 )
{
perror(" tcp_server_init error ");
return -1;
} struct event_base* base = event_base_new(); //加入监听客户端请求连接事件
struct event* ev_listen = event_new(base, listener, EV_READ | EV_PERSIST,
accept_cb, base);
event_add(ev_listen, NULL); event_base_dispatch(base); return 0;
} void accept_cb(int fd, short events, void* arg)
{
evutil_socket_t sockfd; struct sockaddr_in client;
socklen_t len = sizeof(client); sockfd = ::accept(fd, (struct sockaddr*)&client, &len );
evutil_make_socket_nonblocking(sockfd); printf("accept a client %d\n", sockfd); struct event_base* base = (event_base*)arg; //不过为了动态创建一个event结构体
struct event *ev = event_new(NULL, -1, 0, NULL, NULL);
//将动态创建的结构体作为event的回调參数
event_assign(ev, base, sockfd, EV_READ | EV_PERSIST,
socket_read_cb, (void*)ev); event_add(ev, NULL);
} void socket_read_cb(int fd, short events, void *arg)
{
char msg[4096];
struct event *ev = (struct event*)arg;
int len = read(fd, msg, sizeof(msg) - 1); if( len <= 0 )
{
printf("some error happen when read\n");
event_free(ev);
close(fd);
return ;
} msg[len] = '\0';
printf("recv the client msg: %s", msg); char reply_msg[4096] = "I have recvieced the msg: ";
strcat(reply_msg + strlen(reply_msg), msg); write(fd, reply_msg, strlen(reply_msg) );
} typedef struct sockaddr SA;
int tcp_server_init(int port, int listen_num)
{
int errno_save;
evutil_socket_t listener; listener = ::socket(AF_INET, SOCK_STREAM, 0);
if( listener == -1 )
return -1; //同意多次绑定同一个地址。 要用在socket和bind之间
evutil_make_listen_socket_reuseable(listener); struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = 0;
sin.sin_port = htons(port); if( ::bind(listener, (SA*)&sin, sizeof(sin)) < 0 )
goto error; if( ::listen(listener, listen_num) < 0)
goto error; //跨平台统一接口。将套接字设置为非堵塞状态
evutil_make_socket_nonblocking(listener); return listener; error:
errno_save = errno;
evutil_closesocket(listener);
errno = errno_save; return -1;
}
中等:
client代码:
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<errno.h>
#include<unistd.h> #include<stdio.h>
#include<string.h>
#include<stdlib.h> #include<event.h>
#include<event2/bufferevent.h>
#include<event2/buffer.h>
#include<event2/util.h> int tcp_connect_server(const char* server_ip, int port); void cmd_msg_cb(int fd, short events, void* arg);
void server_msg_cb(struct bufferevent* bev, void* arg);
void event_cb(struct bufferevent *bev, short event, void *arg); int main(int argc, char** argv)
{
if( argc < 3 )
{
printf("please input 2 parameter\n");
return -1;
} //两个參数依次是服务器端的IP地址、端口号
int sockfd = tcp_connect_server(argv[1], atoi(argv[2]));
if( sockfd == -1)
{
perror("tcp_connect error ");
return -1;
} printf("connect to server successful\n"); struct event_base* base = event_base_new(); struct bufferevent* bev = bufferevent_socket_new(base, sockfd,
BEV_OPT_CLOSE_ON_FREE); //监听终端输入事件
struct event* ev_cmd = event_new(base, STDIN_FILENO,
EV_READ | EV_PERSIST, cmd_msg_cb,
(void*)bev);
event_add(ev_cmd, NULL); //当socket关闭时会用到回调參数
bufferevent_setcb(bev, server_msg_cb, NULL, event_cb, (void*)ev_cmd);
bufferevent_enable(bev, EV_READ | EV_PERSIST); event_base_dispatch(base); printf("finished \n");
return 0;
} void cmd_msg_cb(int fd, short events, void* arg)
{
char msg[1024]; int ret = read(fd, msg, sizeof(msg));
if( ret < 0 )
{
perror("read fail ");
exit(1);
} struct bufferevent* bev = (struct bufferevent*)arg; //把终端的消息发送给服务器端
bufferevent_write(bev, msg, ret);
} void server_msg_cb(struct bufferevent* bev, void* arg)
{
char msg[1024]; size_t len = bufferevent_read(bev, msg, sizeof(msg));
msg[len] = '\0'; printf("recv %s from server\n", msg);
} void event_cb(struct bufferevent *bev, short event, void *arg)
{ if (event & BEV_EVENT_EOF)
printf("connection closed\n");
else if (event & BEV_EVENT_ERROR)
printf("some other error\n"); //这将自己主动close套接字和free读写缓冲区
bufferevent_free(bev); struct event *ev = (struct event*)arg;
//由于socket已经没有,所以这个event也没有存在的必要了
event_free(ev);
} typedef struct sockaddr SA;
int tcp_connect_server(const char* server_ip, int port)
{
int sockfd, status, save_errno;
struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr) ); server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
status = inet_aton(server_ip, &server_addr.sin_addr); if( status == 0 ) //the server_ip is not valid value
{
errno = EINVAL;
return -1;
} sockfd = ::socket(PF_INET, SOCK_STREAM, 0);
if( sockfd == -1 )
return sockfd; status = ::connect(sockfd, (SA*)&server_addr, sizeof(server_addr) ); if( status == -1 )
{
save_errno = errno;
::close(sockfd);
errno = save_errno; //the close may be error
return -1;
} evutil_make_socket_nonblocking(sockfd); return sockfd;
}
server端代码:
#include<stdio.h>
#include<string.h>
#include<errno.h> #include<event.h>
#include<event2/bufferevent.h> void accept_cb(int fd, short events, void* arg);
void socket_read_cb(bufferevent* bev, void* arg);
void event_cb(struct bufferevent *bev, short event, void *arg);
int tcp_server_init(int port, int listen_num); int main(int argc, char** argv)
{ int listener = tcp_server_init(9999, 10);
if( listener == -1 )
{
perror(" tcp_server_init error ");
return -1;
} struct event_base* base = event_base_new(); //加入监听客户端请求连接事件
struct event* ev_listen = event_new(base, listener, EV_READ | EV_PERSIST,
accept_cb, base);
event_add(ev_listen, NULL); event_base_dispatch(base);
event_base_free(base); return 0;
} void accept_cb(int fd, short events, void* arg)
{
evutil_socket_t sockfd; struct sockaddr_in client;
socklen_t len = sizeof(client); sockfd = ::accept(fd, (struct sockaddr*)&client, &len );
evutil_make_socket_nonblocking(sockfd); printf("accept a client %d\n", sockfd); struct event_base* base = (event_base*)arg; bufferevent* bev = bufferevent_socket_new(base, sockfd, BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(bev, socket_read_cb, NULL, event_cb, arg); bufferevent_enable(bev, EV_READ | EV_PERSIST);
} void socket_read_cb(bufferevent* bev, void* arg)
{
char msg[4096]; size_t len = bufferevent_read(bev, msg, sizeof(msg)); msg[len] = '\0';
printf("recv the client msg: %s", msg); char reply_msg[4096] = "I have recvieced the msg: "; strcat(reply_msg + strlen(reply_msg), msg);
bufferevent_write(bev, reply_msg, strlen(reply_msg));
} void event_cb(struct bufferevent *bev, short event, void *arg)
{ if (event & BEV_EVENT_EOF)
printf("connection closed\n");
else if (event & BEV_EVENT_ERROR)
printf("some other error\n"); //这将自己主动close套接字和free读写缓冲区
bufferevent_free(bev);
} typedef struct sockaddr SA;
int tcp_server_init(int port, int listen_num)
{
int errno_save;
evutil_socket_t listener; listener = ::socket(AF_INET, SOCK_STREAM, 0);
if( listener == -1 )
return -1; //同意多次绑定同一个地址。 要用在socket和bind之间
evutil_make_listen_socket_reuseable(listener); struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = 0;
sin.sin_port = htons(port); if( ::bind(listener, (SA*)&sin, sizeof(sin)) < 0 )
goto error; if( ::listen(listener, listen_num) < 0)
goto error; //跨平台统一接口,将套接字设置为非堵塞状态
evutil_make_socket_nonblocking(listener); return listener; error:
errno_save = errno;
evutil_closesocket(listener);
errno = errno_save; return -1;
}
高等:
client代码:
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<errno.h>
#include<unistd.h> #include<stdio.h>
#include<string.h>
#include<stdlib.h> #include<event.h>
#include<event2/bufferevent.h>
#include<event2/buffer.h>
#include<event2/util.h> int tcp_connect_server(const char* server_ip, int port); void cmd_msg_cb(int fd, short events, void* arg);
void server_msg_cb(struct bufferevent* bev, void* arg);
void event_cb(struct bufferevent *bev, short event, void *arg); int main(int argc, char** argv)
{
if( argc < 3 )
{
//两个參数依次是服务器端的IP地址、端口号
printf("please input 2 parameter\n");
return -1;
} struct event_base *base = event_base_new(); struct bufferevent* bev = bufferevent_socket_new(base, -1,
BEV_OPT_CLOSE_ON_FREE); //监听终端输入事件
struct event* ev_cmd = event_new(base, STDIN_FILENO,
EV_READ | EV_PERSIST,
cmd_msg_cb, (void*)bev); event_add(ev_cmd, NULL); struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr) ); server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1], &server_addr.sin_addr); bufferevent_socket_connect(bev, (struct sockaddr *)&server_addr,
sizeof(server_addr)); bufferevent_setcb(bev, server_msg_cb, NULL, event_cb, (void*)ev_cmd);
bufferevent_enable(bev, EV_READ | EV_PERSIST); event_base_dispatch(base); printf("finished \n");
return 0;
} void cmd_msg_cb(int fd, short events, void* arg)
{
char msg[1024]; int ret = read(fd, msg, sizeof(msg));
if( ret < 0 )
{
perror("read fail ");
exit(1);
} struct bufferevent* bev = (struct bufferevent*)arg; //把终端的消息发送给服务器端
bufferevent_write(bev, msg, ret);
} void server_msg_cb(struct bufferevent* bev, void* arg)
{
char msg[1024]; size_t len = bufferevent_read(bev, msg, sizeof(msg));
msg[len] = '\0'; printf("recv %s from server\n", msg);
} void event_cb(struct bufferevent *bev, short event, void *arg)
{ if (event & BEV_EVENT_EOF)
printf("connection closed\n");
else if (event & BEV_EVENT_ERROR)
printf("some other error\n");
else if( event & BEV_EVENT_CONNECTED)
{
printf("the client has connected to server\n");
return ;
} //这将自己主动close套接字和free读写缓冲区
bufferevent_free(bev); struct event *ev = (struct event*)arg;
event_free(ev);
}
server端代码:
#include<netinet/in.h>
#include<sys/socket.h>
#include<unistd.h> #include<stdio.h>
#include<string.h> #include<event.h>
#include<listener.h>
#include<bufferevent.h>
#include<thread.h> void listener_cb(evconnlistener *listener, evutil_socket_t fd,
struct sockaddr *sock, int socklen, void *arg); void socket_read_cb(bufferevent *bev, void *arg);
void socket_event_cb(bufferevent *bev, short events, void *arg); int main()
{
//evthread_use_pthreads();//enable threads struct sockaddr_in sin;
memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_port = htons(9999); event_base *base = event_base_new();
evconnlistener *listener
= evconnlistener_new_bind(base, listener_cb, base,
LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE,
10, (struct sockaddr*)&sin,
sizeof(struct sockaddr_in)); event_base_dispatch(base); evconnlistener_free(listener);
event_base_free(base); return 0;
} //一个新client连接上服务器了
//当此函数被调用时,libevent已经帮我们accept了这个client。该client的
//文件描写叙述符为fd
void listener_cb(evconnlistener *listener, evutil_socket_t fd,
struct sockaddr *sock, int socklen, void *arg)
{
printf("accept a client %d\n", fd); event_base *base = (event_base*)arg; //为这个client分配一个bufferevent
bufferevent *bev = bufferevent_socket_new(base, fd,
BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(bev, socket_read_cb, NULL, socket_event_cb, NULL);
bufferevent_enable(bev, EV_READ | EV_PERSIST);
} void socket_read_cb(bufferevent *bev, void *arg)
{
char msg[4096]; size_t len = bufferevent_read(bev, msg, sizeof(msg)-1 ); msg[len] = '\0';
printf("server read the data %s\n", msg); char reply[] = "I has read your data";
bufferevent_write(bev, reply, strlen(reply) );
} void socket_event_cb(bufferevent *bev, short events, void *arg)
{
if (events & BEV_EVENT_EOF)
printf("connection closed\n");
else if (events & BEV_EVENT_ERROR)
printf("some other error\n"); //这将自己主动close套接字和free读写缓冲区
bufferevent_free(bev);
}
Libevent使用样例,从简单到复杂的更多相关文章
- Introspector(内省)简单演示样例 与 简单应用
简单演示样例: package com.asdfLeftHand.test; import java.beans.BeanDescriptor; import java.beans.BeanInfo; ...
- Android中关于JNI 的学习(零)简单的样例,简单地入门
Android中JNI的作用,就是让Java可以去调用由C/C++实现的代码,为了实现这个功能.须要用到Anrdoid提供的NDK工具包,在这里不讲怎样配置了,好麻烦,配置了好久. . . 本质上,J ...
- 通过Canvas及File API缩放并上传图片完整演示样例
创建一个只管的用户界面,并同意你控制图片的大小.上传到server端的数据,并不须要处理enctype为 multi-part/form-data 的情况.只一个简单的POST表单处理程序就能够了. ...
- [转] Lodop、C-Lodop使用说明及样例
本文转自:http://www.lodop.net/LodopDemo.html Lodop(标音:劳道谱,俗称:露肚皮)是专业WEB控件,用它既可裁剪输出页面内容,又可用程序代码直接实现 复杂打印. ...
- WEB打印控件Lodop(V6.x)使用说明及样例
WEB打印控件Lodop(V6.x)使用说明及样例 Lodop是专业WEB控件,用它既可裁剪输出页面内容,又可用程序代码生成复杂打印页. 控件功能强大,却简单易用,所有调用如同JavaScript扩展 ...
- Linux下用OTL操作MySql(包含自己封装的类库及演示样例代码下载)
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/ClamReason/article/details/23971805 首先重点推荐介绍otl介绍及使 ...
- Thrift的安装和简单演示样例
本文仅仅是简单的解说Thrift开源框架的安装和简单使用演示样例.对于具体的解说,后面在进行阐述. Thrift简述 ...
- socket编程——一个简单的样例
从一个简单的使用TCP样例開始socket编程,其基本过程例如以下: server client ++ ...
- JBoss 系列九十六:JBoss MSC - 简介及一个简单演示样例
什么是 JBoss MSC JBoss MSC 即 JBoss Modular Service Container,是第三代 JBoss 产品 JBoss 7和WildFfly的内核,JBoss MS ...
随机推荐
- lua中打印所以类型功能实现table嵌套table
lua中打印所以类型功能实现 本人測试 number.string.bool.nil.table嵌套table.userdata没问题 共享一下有什么问题请拍砖 代码例如以下 cclog = func ...
- asp.net2.0安全性(2)--用户个性化设置(2)--转载来自车老师
上一篇我们用Profile.age等方式可以读取用户的年龄和其它的信息,但有的时候我们要查询显示所有用户的信息,但asp.net没有提供查询所有用户信息的功能,我们只能对现有的用户逐一查询其Profi ...
- 编译mapnik(win7 环境下vs2008编译mapnik 0.7.1 成功)
编译mapnik(win7 环境下vs2008编译mapnik 0.7.1 成功) ------by wangsh 2012.02.22 Mapnik 是一个开源的 Python/C++ 地图渲染引 ...
- 带dos调试窗口的win32程序
#pragma comment( linker, "/subsystem:\"console\" /entry:\"WinMainCRTStartup\&quo ...
- 关于python抓取google搜索结果的若干问题
关于python抓取google搜索结果的若干问题 前一段时间一直在研究如何用python抓取搜索引擎结果,在实现的过程中遇到了很多的问题,我把我遇到的问题都记录下来,希望以后遇到同样问题的童 ...
- Js版游戏打砖块开发过程详细
最近对js的小游戏开发来了兴趣,前段时间由于回答度娘知道的提问写了个贪吃蛇,虽然难度不大并不复杂,感觉还挺有意思.感觉小时候玩过的什么俄罗斯方块,坦克大战什么的都可以试着用js实现下,这天来了兴致又想 ...
- HDU4549 M斐波那契数
M斐波那契数列 题目分析: M斐波那契数列F[n]是一种整数数列,它的定义例如以下: F[0] = a F[1] = b F[n] = F[n-1] * F[n-2] ( n > 1 ) 如今给 ...
- 出现Data Tools 与VS 不兼容问题
转载自:http://www.yishimei.cn/network/73.html 相信很多人都遇到了“此版本的SQL Server Data Tools与此计算机中安装的数据库运行时组件不兼容”这 ...
- 让delphi程序不受WINDOWS日期格式的影响(使用SetLocaleInfo函数和Application.UpdateFormatSettings)
如果WINDOWS系统的短日期格式为“yyyy/m/d”,执行下面的代码会报错:2013-01-29 00:00:00不是合法的日期procedure TFrmQuerySale.FormShow(S ...
- [LeetCode] Unique Paths 2
Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. How m ...