轻量级网络库Libevent对高效的I/O进行了封装,提供统一的API,我们调用API就会很方便,要搞清楚每个API背后的操作。
什么是高效的I/O???
如Linux中独有的epoll,windows的IOCP,BSD的Kqueque
我使用的是libevent2.0.21版本, Libevent2.0版本以后提供了bufferevent 提供了易用的API,bufferevent 解决了粘包等问题,我们在写程序的时候就不用自己管理缓冲区了。
关于tcp网络socket编程的一系列流程 可以查看
接下来说libevent的使用教程
- 第一步
//创建一个event_base struct event_base *base = event_base_new();
-
第二步
//创建并绑定一个event struct event *event_listen = event_new(base, sockfd, EV_READ|EV_PERSIST, CallBack_Func, (void*)base);
-
第三步
//添加事件 event_add(even_listen, NULL);
-
第四步
//事件循环 event_base_dispatch(base);
- 第五步
1.设置描述符c(accept之后返回的描述符fd)为nonblocking
Linux中将socket设置为非阻塞 int flag = fcntl(sockfd, F_GETFL, 0); fcntl(sockfd, F_SETFL, flag|O_NONBLOCK);
2.创建一个bufferevent,struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
3.调用bufferevent_setcb(bev, Read_cb, Write_cb, bufferent_event_erro3, NULL);
4.调用bufferevent_enable(bev, EV_READ | EV_RWRITE | EV_PERSIST); 启用read/write事件
下边就是整个服务器调用libevent的代码编程
//
// Created by yanpan on 2019/4/26.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <iostream>
#include <event.h>
using namespace std;
//#define address 127.0.0.1
//#define port 8888
void OnRead(struct bufferevent *bev, void *arg)
{
cout<<"bufferent_event_ok happened ....."<<endl;
evutil_socket_t sfd = bufferevent_getfd(bev);
int recv_size = 0;
char buf[100];
memset(buf,0,sizeof(char)*100);
std::cout<<"enter buf==="<<buf<<std::endl;
if ((recv_size = bufferevent_read(bev, buf, 100)) > 0) // 读取前100位的数据
{
}
std::cout<<"get buf==="<<buf<<std::endl;
int write_num = bufferevent_write(bev, "ok", 2);
cout << write_num << " characters written" << endl;
}
void bufferent_event_erro3(struct bufferevent *bev, short event, void *arg)
{
evutil_socket_t sfd = bufferevent_getfd(bev);
bufferevent_free(bev);
}
void OnAccept(int sockfd, short iEvent, void *arg)
{
cout<< "OnAccept happended >>>>> " <<endl;
struct sockaddr_in cli;
socklen_t len = sizeof(cli);
evutil_socket_t fd = accept(sockfd, (struct sockaddr*)&cli, &len);
if(-1 == fd)
{
cout<< "fd error" <<endl;
return;
}
struct event_base* base = static_cast<event_base*> (arg);
int flag = EV_READ | EV_PERSIST;
evutil_make_socket_nonblocking(fd); //将fd设置成非阻塞
struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(bev, OnRead, NULL, bufferent_event_erro3, NULL);
bufferevent_enable(bev, flag);
}
int main()
{
int sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (-1 == sockfd)
return 0;
struct sockaddr_in ser;
ser.sin_family = PF_INET;
ser.sin_addr.s_addr = inet_addr("127.0.0.1");
ser.sin_port = htons(8888);
int ret = bind(sockfd, (struct sockaddr*)&ser, sizeof(ser));
if(-1 == ret)
return 0;
int listenfd = listen(sockfd, 5);
if(-1 == listenfd)
return 0;
//初始化base
struct event_base* base = event_base_new();
struct event *even_listen = event_new(base, sockfd, EV_READ|EV_PERSIST, OnAccept, (void*)base);
//添加事件
event_add(even_listen, NULL);
//事件循环
event_base_dispatch(base);
return 0;
}
坚持✊