转载请注明出处:http://blog.csdn.net/luotuo44/article/details/39670221

本文从简单到复杂,展示如何使用libevent。网上的许多例子都是只有服务器端的,本文里面客户端和服务器端都有,以飨读者。

关于libevent编程时的一些疑问可以阅读《libevent编程疑难解答》。假如读者还想了解libevent的具体实现,可以阅读《libevent源码分析》系统文章。

不说这么多了,直接上代码。

初等:

客户端代码:

#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 < )
{
printf("please input 2 parameter\n");
return -;
} //两个参数依次是服务器端的IP地址、端口号
int sockfd = tcp_connect_server(argv[], atoi(argv[]));
if( sockfd == -)
{
perror("tcp_connect error ");
return -;
} 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 ;
} void cmd_msg_cb(int fd, short events, void* arg)
{
char msg[]; int ret = read(fd, msg, sizeof(msg));
if( ret <= )
{
perror("read fail ");
exit();
} int sockfd = *((int*)arg); //把终端的消息发送给服务器端
//为了简单起见,不考虑写一半数据的情况
write(sockfd, msg, ret);
} void socket_read_cb(int fd, short events, void *arg)
{
char msg[]; //为了简单起见,不考虑读一半数据的情况
int len = read(fd, msg, sizeof(msg)-);
if( len <= )
{
perror("read fail ");
exit();
} 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, , 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 == ) //the server_ip is not valid value
{
errno = EINVAL;
return -;
} sockfd = ::socket(PF_INET, SOCK_STREAM, );
if( sockfd == - )
return sockfd; status = ::connect(sockfd, (SA*)&server_addr, sizeof(server_addr) ); if( status == - )
{
save_errno = errno;
::close(sockfd);
errno = save_errno; //the close may be error
return -;
} evutil_make_socket_nonblocking(sockfd); return sockfd;
}

服务器端代码:

#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(, );
if( listener == - )
{
perror(" tcp_server_init error ");
return -;
} 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 ;
} 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, -, , 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[];
struct event *ev = (struct event*)arg;
int len = read(fd, msg, sizeof(msg) - ); if( len <= )
{
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[] = "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, );
if( listener == - )
return -; //允许多次绑定同一个地址。要用在socket和bind之间
evutil_make_listen_socket_reuseable(listener); struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ;
sin.sin_port = htons(port); if( ::bind(listener, (SA*)&sin, sizeof(sin)) < )
goto error; if( ::listen(listener, listen_num) < )
goto error; //跨平台统一接口,将套接字设置为非阻塞状态
evutil_make_socket_nonblocking(listener); return listener; error:
errno_save = errno;
evutil_closesocket(listener);
errno = errno_save; return -;
}

中等:

客户端代码:

#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 < )
{
printf("please input 2 parameter\n");
return -;
} //两个参数依次是服务器端的IP地址、端口号
int sockfd = tcp_connect_server(argv[], atoi(argv[]));
if( sockfd == -)
{
perror("tcp_connect error ");
return -;
} 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 ;
} void cmd_msg_cb(int fd, short events, void* arg)
{
char msg[]; int ret = read(fd, msg, sizeof(msg));
if( ret < )
{
perror("read fail ");
exit();
} struct bufferevent* bev = (struct bufferevent*)arg; //把终端的消息发送给服务器端
bufferevent_write(bev, msg, ret);
} void server_msg_cb(struct bufferevent* bev, void* arg)
{
char msg[]; 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, , 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 == ) //the server_ip is not valid value
{
errno = EINVAL;
return -;
} sockfd = ::socket(PF_INET, SOCK_STREAM, );
if( sockfd == - )
return sockfd; status = ::connect(sockfd, (SA*)&server_addr, sizeof(server_addr) ); if( status == - )
{
save_errno = errno;
::close(sockfd);
errno = save_errno; //the close may be error
return -;
} evutil_make_socket_nonblocking(sockfd); return sockfd;
}

服务器端代码:

#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(, );
if( listener == - )
{
perror(" tcp_server_init error ");
return -;
} 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 ;
} 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[]; size_t len = bufferevent_read(bev, msg, sizeof(msg)); msg[len] = '\0';
printf("recv the client msg: %s", msg); char reply_msg[] = "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, );
if( listener == - )
return -; //允许多次绑定同一个地址。要用在socket和bind之间
evutil_make_listen_socket_reuseable(listener); struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ;
sin.sin_port = htons(port); if( ::bind(listener, (SA*)&sin, sizeof(sin)) < )
goto error; if( ::listen(listener, listen_num) < )
goto error; //跨平台统一接口,将套接字设置为非阻塞状态
evutil_make_socket_nonblocking(listener); return listener; error:
errno_save = errno;
evutil_closesocket(listener);
errno = errno_save; return -;
}

高等:

客户端代码:

#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 < )
{
//两个参数依次是服务器端的IP地址、端口号
printf("please input 2 parameter\n");
return -;
} struct event_base *base = event_base_new(); struct bufferevent* bev = bufferevent_socket_new(base, -,
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, , sizeof(server_addr) ); server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(atoi(argv[]));
inet_aton(argv[], &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 ;
} void cmd_msg_cb(int fd, short events, void* arg)
{
char msg[]; int ret = read(fd, msg, sizeof(msg));
if( ret < )
{
perror("read fail ");
exit();
} struct bufferevent* bev = (struct bufferevent*)arg; //把终端的消息发送给服务器端
bufferevent_write(bev, msg, ret);
} void server_msg_cb(struct bufferevent* bev, void* arg)
{
char msg[]; 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);
}

服务器端代码:

#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, , sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_port = htons(); event_base *base = event_base_new();
evconnlistener *listener
= evconnlistener_new_bind(base, listener_cb, base,
LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE,
, (struct sockaddr*)&sin,
sizeof(struct sockaddr_in)); event_base_dispatch(base); evconnlistener_free(listener);
event_base_free(base); return ;
} //一个新客户端连接上服务器了
//当此函数被调用时,libevent已经帮我们accept了这个客户端。该客户端的
//文件描述符为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; //为这个客户端分配一个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[]; size_t len = bufferevent_read(bev, msg, sizeof(msg)- ); 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);
}

http://blog.csdn.net/luotuo44/article/details/39670221

Libevent使用例子,从简单到复杂的更多相关文章

  1. AgileEAS.NET SOA 中间件平台.Net Socket通信框架-简单例子-实现简单的服务端客户端消息应答

    一.AgileEAS.NET SOA中间件Socket/Tcp框架介绍 在文章AgileEAS.NET SOA 中间件平台Socket/Tcp通信框架介绍一文之中我们对AgileEAS.NET SOA ...

  2. 【Networking】Libevent客户端例子

    [原]Libevent客户端例子 时间 -- :: luotuo44的专栏 原文 http://blog.csdn.net/luotuo44/article/details/34416429 主题 l ...

  3. [z]Libevent使用例子,从简单到复杂

    [z]http://blog.csdn.net/luotuo44/article/details/39670221 本文从简单到复杂,展示如何使用libevent.网上的许多例子都是只有服务器端的,本 ...

  4. IOS Animation-CABasicAnimation例子(简单动画实现)

    这些例子都是CABasicAnimation的一些简单实现的动画,例如移动.透明度.翻转等等.方法里面传入一个CALayer类或者子类就可以了. 下面是用swift实现的,这些方法我们也可以用作公共类 ...

  5. Qt使用一个事件队列对所有发出的事件进行维护(QObject的event()函数相当于dispatch函数),用EventLabel 继承QLabel作为例子(简单明了) good

    事件(event)是由系统或者 Qt 本身在不同的时刻发出的.当用户按下鼠标.敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件.一些事件在对用户操作做出响应时发出,如键盘事件等:另一些事 ...

  6. ExecutorService与Executors例子的简单剖析

    对于多线程有了一点了解之后,那么来看看java.lang.concurrent包下面的一些东西.在此之前,我们运行一个线程都是显式调用了Thread的start()方法.我们用concurrent下面 ...

  7. ExecutorService与Executors例子的简单剖析(转)

    对于多线程有了一点了解之后,那么来看看java.lang.concurrent包下面的一些东西.在此之前,我们运行一个线程都是显式调用了 Thread的start()方法.我们用concurrent下 ...

  8. 转一篇OpenSSL的例子:简单的TLS服务器

    原名:Simple TLS Server 原址:https://wiki.openssl.org/index.php/Simple_TLS_Server Windows下就不要从源码编译OpenSSL ...

  9. amin例子的简单研究

    amin这个例子,使用了比较复杂高阶的qml技巧,但是也有局限性.下面分3个部分,分别是界面部分,算法部分和扩展部分,简单地对这个问题进行理解.        由衷感谢:http://amin-ahm ...

随机推荐

  1. 条款10:让operator=返回一个reference to *this

    例如对象x,y,z.要实现连锁赋值(假设operator=已经重载过了):x = y = z,那么operator=则必须返回一个*this. 注意这个条款不仅仅适合于operator=,对于oper ...

  2. 【SQL查询】视图_view

    转自:http://database.e800.com.cn/articles/2009/719/1248015564465_1.html 视图是从一个或几个基本表(或视图)导出的表.它与基本表不同, ...

  3. C++友元函数实现

    友元函数是一种特殊的函数,它必须要在类中进行声明,但其本身并不是类的成员函数,但友元函数可以访问类的私有成员变量. 友元函数的好处: 1.实现类之间的数据共享 2.提高程序运行效率,方便编程 友元函数 ...

  4. Android学习之Activity跳转与传值

    Activity跳转与传值,主要是通过Intent类,Intent的作用是激活组件和附带数据. 一.Activity跳转 方法一 Intent intent = new Intent(A.this, ...

  5. 旧书重温:0day2【9】第六章 攻击c++的虚函数

    不知不觉,我们学到了0day2的第六章形形色色的内存攻击技术!其中,这张很多东西都是理论的东西,不过!我们还是要想办法还原下发生的现场! 其中部分文章截图 http://user.qzone.qq.c ...

  6. 旧书重温:0day2【7】堆溢出实验

    相关文章我拍成了照片,放在了我的QQ空间不是做广告(一张一张的传太麻烦了)http://user.qzone.qq.com/252738331/photo/V10U5YUk2v0ol6/    密码9 ...

  7. OpenCV-Python cv2.imdecode()和cv2.imencode() 图片解码和编码

    cv2.imdecode()函数从指定的内存缓存中读取数据,并把数据转换(解码)成图像格式;主要用于从网络传输数据中恢复出图像. cv2.imencode()函数是将图片格式转换(编码)成流数据,赋值 ...

  8. phpcms v9 csdn老手记录

    http://blog.csdn.net/yanhui_wei/article/category/1220735

  9. MySql必知必会实战练习(六)游标

    游标主要用于交互式应用,滚动屏幕上的数据,并对数据进行浏览或做出更改 看一下下面的例子: drop procedure IF EXISTS processorders; create procedur ...

  10. 转载.Avalon-MM 阿窝龙妹妹应用笔记

    Avalon Interface Special http://www.altera.com.cn/literature/manual/mnl_avalon_spec.pdf Avalon总线是SOP ...