转载请注明出处: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. hibernate12--注解

    在之前的基础上删除hbm.xml映射文件 之后修改实体类内容 /** * 部门的实体类 * strategy对应的就是主键生成策略 * GenerationType: * 01.auto:自动选择合适 ...

  2. Celery分布式应用

    最近有应用需要部署到不同的服务器上运行,但是有没有PBS这样的调度系统,就想起来Python的调度神器 Celery.现在针对我的实际应用做一些记录. 1. 安装 因为我并不注重结果而是把命令拿到不同 ...

  3. Lua基础---流程控制语句

    Lua提供了if语句和if else语句作为流程控制语句,当然,符合C的特点,流程语句之间可以实现嵌套操作,当然流程控制也可以和循环体结合进行控制. 1.if语句 if(布尔表达式) then --[ ...

  4. 解决 Laravel/Lumen 出现 "Please provide a valid cache path" 问题

    解决 Laravel/Lumen 出现 "Please provide a valid cache path" 问题 解决 Laravel/Lumen 出现 "Pleas ...

  5. 在spring配置文件中的 <context:property-placeholder/>用途

    location属性为 具体配置文件的classpath:地址 (可以取配置文件中的值利用${key}的形式,而不用多次写值) 1.这样一来就可以为spring配置的bean的属性设置值了,比如spr ...

  6. python之pandas数据筛选和csv操作

    本博主要总结DaraFrame数据筛选方法(loc,iloc,ix,at,iat),并以操作csv文件为例进行说明 1. 数据筛选 a b c (1)单条件筛选 df[df[] # 如果想筛选a列的取 ...

  7. 批量插入数据利器之SqlBulkCopy

    工作中要频繁的处理一些数据导入,又不想手工去做,因此用了神器SqlBulkCopy.在MSDN查看了此类的帮助文档几经波折终于搞定,记录下来方便以后查阅. MSDN实例: using System.D ...

  8. lvds配置

    基于Altera FPGA的LVDS配置应用一例 在特权同学发表博文<Cyclone III的LVDS接口注意事项>后,不少网友发邮件询问LVDS具体应用的一些问题.这些网友,归根到底,估 ...

  9. fn project 扩展

    目前支持的扩展方式   Listeners - listen to API events such as a route getting updated and react accordingly. ...

  10. #51单片机#蓝牙模块(ATK-SPP-HC06从机串口)的使用方法

    #include <AT89X51.H> #include <intrins.h> // 函数原形定义 #define uchar unsigned char #define ...