上一篇讲了Libevent一些常用的API,但是没有实际的demo,多多少少有点难理解,那么接下来就直接上代码
(执行下面两个命令生成可执行程序)
gcc client.c -o client -levent_core(指定库名)
export LD_LIBRARY_PATH=/usr/local/lib(因为event_core在这个目录在,所以要加载该目录下的动态库)
client
#include<stdlib.h>
#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<event2/event.h>
#include<event2/bufferevent.h>
#include<event2/buffer.h>
//当向终端输入数据的时候,调用该函数
void callback_input(evutil_socket_t fd, short falg, void *arg)
{
char buf[4096]={0};
int len=read(fd,buf,sizeof(buf));//读取终端输入的数据
if(len==1)
{
printf("please input message");
return;
}
bufferevent_write((struct bufferevent*)arg,buf,sizeof(buf));//向服务器发送数据
}
//当服务器发送数据过来的时候,调用该函数
void callback_read(struct bufferevent *buffer, void *arg)
{
char buf[4096]={0};
bufferevent_read(buffer,buf,sizeof(buf));//读取服务器发过来的数据
printf("server send:%s\n",buf);
printf("please input message to server:");
fflush(stdout);//刷新终端,这个很重要,不然看不到上面一句话
}
//当服务器关闭的时候,或者bufferevent缓冲区有问题的时候,调用该函数
void callback_event(struct bufferevent *buffer, short what, void *arg)
{
if(what&BEV_EVENT_EOF)
{
printf("connection closed\n");
}
else if(what&BEV_EVENT_ERROR)
{
printf("some other error\n");
}
bufferevent_free(buffer);
}
//客户端初始化函数
int client_init(char *ip,char *port)
{
evutil_socket_t socketfd=socket(AF_INET,SOCK_STREAM,0);//创建TCP套接字
if(socketfd<0)
{
perror("socket error");
return -1;
}
struct sockaddr_in addr;
addr.sin_family=AF_INET;//协议族
addr.sin_port=htons(atoi(port));//将本地端口转化为网络端口
inet_aton(ip,&addr.sin_addr);//将本地IP,转化为网络IP
int status=connect(socketfd,(struct sockaddr*)&addr,sizeof(addr));//连接服务器
if(status!=0)
{
perror("connect error");
return -2;
}
evutil_make_socket_nonblocking(socketfd);//设置为非阻塞
return socketfd;
}
int main(int argc,char **argv)
{
if(argc<3)
{
printf("arguement too less,format is[./a.out ip port]\n"); //表示要这样运行程序 ./a.out 127.0.0.0 8080
return -1;
}
evutil_socket_t socketfd=client_init(argv[1],argv[2]);//初始化,连接服务器
if(socketfd<0)
{
perror("client_init error");
return -2;
}
printf("connect server success......\n");
struct event_base *base=event_base_new();//创建事件集合,用来管理事件,这是使用Libevent所做的第一步
if(base==NULL)
{
evutil_closesocket(socketfd);//关闭套接字
perror("event_base_new error");
return -3;
}
struct bufferevent *buffer=bufferevent_socket_new(base,socketfd,BEV_OPT_CLOSE_ON_FREE);//创建一个基于socket的bufferevent缓冲区,利用产生的bufferevent进行读写操作,BEV_OPT_CLOSE_ON_FREE表示释放 bufferevent 时关闭底层传输端口
if(buffer==NULL)
{
evutil_closesocket(socketfd);
perror("bufferevent_socket_new error");
return -4;
}
printf("please input message to server:");
fflush(stdout);
struct event *event=event_new(base,STDIN_FILENO,EV_READ|EV_PERSIST,callback_input,buffer);//注册终端响应事件,当往终端输入数据的时候会调用input函数
if(event==NULL)
{
evutil_closesocket(socketfd);
bufferevent_free(buffer);//释放bufferevent
perror("event_new error");
return -5;
}
event_add(event,NULL);//将注册的事件变为未决状态
bufferevent_setcb(buffer,callback_read,NULL,callback_event,event);//当bufferevent缓冲区有内容可以读取/出现问题的时候调用read/event回调函数
bufferevent_enable(buffer,EV_READ|EV_PERSIST);//启用回调水位
event_base_dispatch(base);//循环
event_free(event);//释放event
event_base_free(base);//释放base
}
server(因为上面写了很多备注,下面就不写咯)
#include<stdlib.h>
#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<event2/event.h>
#include<event2/bufferevent.h>
#include<event2/buffer.h>
#include<event2/util.h>
static int num=0;
//当客户端发送数据过来的时候,调用该函数
void callback_read(struct bufferevent *buffer, void *arg)
{
char readBuf[4096]={0};
bufferevent_read(buffer,readBuf,sizeof(readBuf));
printf("client%d send:%s",(int)arg,readBuf);
bufferevent_write(buffer,readBuf,sizeof(readBuf));
}
//当客户端关闭或者bufferevent缓冲区有问题的时候,调用该函数
void callback_event(struct bufferevent *buffer, short what, void *arg)
{
if(what&BEV_EVENT_EOF)
{
printf("client%d closed\n",(int)arg);
}
else if(what&BEV_EVENT_ERROR)
{
printf("some other error\n");
}
bufferevent_free(buffer);
}
//当有客户端连接时,调用该函数
void callback_accept(evutil_socket_t fd, short flag, void *arg)
{
struct event_base *base=(struct event_base *)arg;
int socketfd=accept(fd,NULL,NULL);
if(socketfd<0)
{
perror("accept error");
return;
}
num++;
printf("client%d connect success......\n",num);
struct bufferevent *buffer=bufferevent_socket_new(base,socketfd,BEV_OPT_CLOSE_ON_FREE);
if(buffer==NULL)
{
perror("bufferevent_socket_new error");
return;
}
bufferevent_setcb(buffer,callback_read,NULL,callback_event,num);
bufferevent_enable(buffer,EV_READ|EV_PERSIST);
}
//服务器初始化函数
int server_init(int port,int listennum)
{
int listenfd=socket(AF_INET,SOCK_STREAM,0);
if(listenfd<0)
{
perror("socker error");
return -1;
}
evutil_make_listen_socket_reuseable(listenfd);//端口可以重复绑定
struct sockaddr_in addr;
addr.sin_port=htons(port);
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=INADDR_ANY;//任何client都可以访问,不指定IP,这里也可以写0
int status=bind(listenfd,(struct sockaddr *)&addr,sizeof(addr));//绑定套接字
if(status!=0)
goto Error;
status=listen(listenfd,listennum);//开始监听
if(status!=0)
goto Error;
evutil_make_socket_nonblocking(listenfd);
return listenfd;
Error:
printf("error");
evutil_closesocket(listenfd);
return -2;
}
int main(int argc,char **argv)
{
evutil_socket_t listenfd=server_init(8080,20);//服务器初始化,端口为8080,listen个数为20
if(listenfd<0)
{
perror("server_init error");
return -1;
}
struct event_base *base=event_base_new();
if(base==NULL)
{
perror("event_base_new error");
return -2;
}
struct event * event=event_new(base,listenfd,EV_READ|EV_PERSIST,callback_accept,base);//注册事件,当client连接成功时,调用accept函数
if(event==NULL)
{
perror("event_new error");
event_base_free(base);
return -3;
}
event_add(event,NULL);
event_base_dispatch(base);
event_base_free(base);
event_free(event);
evutil_closesocket(listenfd);//关闭套接字
return 0;
}