libevent代码编写
最简单的实践
经过上一篇对libevent的分析,这篇就开始实践使用libevent进行编程。
编译时要指定事件库,添加 -levent 参数。
gcc -o ev ev.c -levent
运行时出现libevent-2.1.so.7找不到的解决办法
error while loading shared libraries: libevent-2.1.so.7: cannot open shared object file: No such file or directory
产生原因:
libevent动态库在默认安装时,存放的路径在/usr/local/lib下,不在系统的默认查找路径内。
解决办法有两个:
(1)将该路径放在系统查找路径内。
sudo echo "/usr/local/lib" >> /etc/ld.so.conf
sudo ldconfig
这种方法仅永久有效。
(2)添加环境变量的方法,添加 export LD_LIBRARY_PATH=XXX
export LD_LIBRARY_PATH=/usr/local/lib/
这种方法仅当前有效。
1、构建整体框架
(1)创建event_base对象。
(2)开启事件循环。
(3)销毁event_base对象。
#include <event.h>
int main()
{
struct event_base *base = event_base_new();
event_base_dispatch(base);
event_base_free(base);
return 0;
}
2、构建listener对象----接收连接
evconnlistener_new_bind()创建listener对象。
#include <event.h>
#include <event2/listener.h>
#include <stdio.h>
void accept_cb(struct evconnlistener *listen,evutil_socket_t fd,struct sockaddr *sock,int socklen,void *arg)
{
// 连接的建立---接收连接
char ip[32] = { 0 };
evutil_inet_ntop(AF_INET, sock, ip, sizeof(ip) - 1);
printf("accept a client fd:%d, ip:%s\n", fd, ip);
}
int main()
{
// 创建事件对象
struct event_base *base = event_base_new();
// listener
struct sockaddr_in sin = { 0 };
sin.sin_family = AF_INET;
sin.sin_port = htons(8888);
struct evconnlistener *listen = evconnlistener_new_bind(base, accept_cb,base,
LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,512,(struct sockaddr *)&sin,sizeof(sin));
// 事件循环
event_base_dispatch(base);
// 销毁evconnlistener对象
evconnlistener_free(listen);
// 销毁事件对象
event_base_free(base);
return 0;
}
3、构建bufferevent对象----主动连接
bufferevent_socket_new()创建bufferevent对象。
#include <event.h>
#include <event2/listener.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void connected_cb(struct bufferevent *bev,short what,void *ctx)
{
if (what == BEV_EVENT_CONNECTED)//连接建立成功
{
printf("connect server successed.\n");
}
else
printf("connect server failed.\n");
}
int main()
{
// 创建事件对象
struct event_base *base = event_base_new();
// 连接的建立---主动连接
struct sockaddr_in sin = { 0 };
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr("192.168.1.105");
sin.sin_port = htons(9999);
struct bufferevent *ev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);//-1表示自动创建fd
bufferevent_socket_connect(ev, (struct sockaddr *)&sin, sizeof(sin));
// 注册事件回调
bufferevent_setcb(ev, NULL, NULL, connected_cb, NULL);
// 事件循环
event_base_dispatch(base);
// 销毁bufferevent对象
bufferevent_free(ev);
// 销毁事件对象
event_base_free(base);
return 0;
}
4、注册读写事件
(1)bufferevent_socket_new()创建bufferevent对象。
(2)bufferevent_setcb()注册读写事件。
(3)bufferevent_enable()打开事件。
(4)bufferevent_get_input(),读回调函数中读取读缓冲区。
(5)读回调中界定数据包,解析数据包,分发业务逻辑。界定数据包是否完整主要通过 特殊字符和固定长度来分割。
(6)在读回调中解析完数据可以调用bufferevent_write()发送数据。
(7)处理连接断开调用bufferevent_free()。
#include <event.h>
#include <event2/listener.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// 处理连接断开
void socket_event_callback(struct bufferevent *bev, short events, void *arg)
{
if (events &BEV_EVENT_EOF)//read=0
{
printf("connection closed\n");
}
else if (events & BEV_EVENT_ERROR)//strerro(errno)
{
printf("some other error\n");
}
else if (events &BEV_EVENT_TIMEOUT)
printf("time out\n");
bufferevent_free(bev);// close(fd)
}
// 读回调
void socket_read_callback(struct bufferevent *bev, void *arg)
{
// 读取读缓冲区
struct evbuffer *evbuf = bufferevent_get_input(bev);
// 界定数据包,解析数据包,分发业务逻辑
char *msg = evbuffer_readln(evbuf, NULL, EVBUFFER_EOL_LF);// \n作为数据包分隔符
if (!msg)
return;
printf("server read the data:%s\n", msg);
char reply[4096] = { 0 };
sprintf(reply, "recvieced msg: %s\n", msg);
// 需要自己释放资源
free(msg);
bufferevent_write(bev, reply, strlen(reply));
}
void accept_cb(struct evconnlistener *listen,evutil_socket_t fd,struct sockaddr *sock,int socklen,void *arg)
{
struct event_base *base = (struct event_base *)arg;
// 连接的建立---接收连接
char ip[32] = { 0 };
evutil_inet_ntop(AF_INET, sock, ip, sizeof(ip) - 1);
printf("accept a client fd:%d, ip:%s\n", fd, ip);
struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
// 注册读事件
bufferevent_setcb(bev, socket_read_callback, NULL, socket_event_callback, NULL);//写事件回调一般为NULL
bufferevent_enable(bev, EV_READ | EV_PERSIST);
}
int main()
{
// 创建事件对象
struct event_base *base = event_base_new();
// listener
struct sockaddr_in sin = { 0 };
sin.sin_family = AF_INET;
sin.sin_port = htons(8888);
struct evconnlistener *listen = evconnlistener_new_bind(base, accept_cb,base,
LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,512,(struct sockaddr *)&sin,sizeof(sin));
// 事件循环
event_base_dispatch(base);
// 销毁evconnlistener对象
evconnlistener_free(listen);
// 销毁事件对象
event_base_free(base);
return 0;
}
完整示例代码
#include <event.h>
#include <event2/listener.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// 处理连接断开
void socket_event_callback(struct bufferevent *bev, short events, void *arg)
{
if (events &BEV_EVENT_EOF)//read=0
{
printf("connection closed\n");
}
else if (events & BEV_EVENT_ERROR)//strerro(errno)
{
printf("some other error\n");
}
else if (events &BEV_EVENT_TIMEOUT)
printf("time out\n");
bufferevent_free(bev);// close(fd)
}
// 读回调
void socket_read_callback(struct bufferevent *bev, void *arg)
{
// 读取读缓冲区
struct evbuffer *evbuf = bufferevent_get_input(bev);
// 界定数据包,解析数据包,分发业务逻辑
char *msg = evbuffer_readln(evbuf, NULL, EVBUFFER_EOL_LF);// \n作为数据包分隔符
if (!msg)
return;
printf("server read the data:%s\n", msg);
char reply[4096] = { 0 };
sprintf(reply, "recvieced msg: %s\n", msg);
// 需要自己是否资源
free(msg);
bufferevent_write(bev, reply, strlen(reply));
}
void connected_cb(struct bufferevent *bev,short what,void *ctx)
{
if (what == BEV_EVENT_CONNECTED)//连接建立成功
{
printf("connect server successed.\n");
}
else
printf("connect server failed.\n");
}
void accept_cb(struct evconnlistener *listen,evutil_socket_t fd,struct sockaddr *sock,int socklen,void *arg)
{
struct event_base *base = (struct event_base *)arg;
// 连接的建立---接收连接
char ip[32] = { 0 };
evutil_inet_ntop(AF_INET, sock, ip, sizeof(ip) - 1);
printf("accept a client fd:%d, ip:%s\n", fd, ip);
struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
// 注册读事件
bufferevent_setcb(bev, socket_read_callback, NULL, socket_event_callback, NULL);//写事件回调一般为NULL
bufferevent_enable(bev, EV_READ | EV_PERSIST);
/*
// 断开连接
evutil_closesocket(fd);
// 连接的建立---主动连接
struct sockaddr_in sin = { 0 };
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr("192.168.1.105");
sin.sin_port = htons(9999);
struct bufferevent *ev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);//-1表示自动创建fd
bufferevent_socket_connect(ev, (struct sockaddr *)&sin, sizeof(sin));
// 注册写事件
bufferevent_setcb(ev, NULL, NULL, connected_cb, NULL);
*/
}
int main()
{
// 创建事件对象
struct event_base *base = event_base_new();
// listener
struct sockaddr_in sin = { 0 };
sin.sin_family = AF_INET;
sin.sin_port = htons(8888);
struct evconnlistener *listen = evconnlistener_new_bind(base, accept_cb,base,
LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,512,(struct sockaddr *)&sin,sizeof(sin));
// 事件循环
event_base_dispatch(base);
// 销毁evconnlistener对象
evconnlistener_free(listen);
// 销毁事件对象
event_base_free(base);
return 0;
}
总结
libevent实践中编写了处理接收连接、处理主动连接、读数据、写数据的代码。