Libevent实现TCP客户端服务器
Libevent实现TCP客户端服务器
17-libevent实现Tcp服务器流程_bilibili_哔哩哔哩_bilibili
文章目录
- Libevent实现TCP客户端服务器
- 1.服务器端实现流程
- 2.服务器端代码实现
- 3.客户端实现流程
- 4.客户端代码实现
1.服务器端实现流程
1.创建 event_base
2.创建服务器连接监听器 evconnlister_new_bind() ;
3.在 evconnlister_new_bind 的回调函数中,处理接受连接后的操作
4.回调函数被调用,说明有一个新客户端连接上来。会得到一个新fd,用于跟客户端通信(读、写)
5.使用 bufferevnet_socket_new()创建一个新bufferevnet事件,将fd 封装到这个事件对象中
6.使用 bufferevent_setcb 给这个事件对象的 read、write、event 设置回调
7.设置 bufferevnet 的读写缓冲区 enable/disable
8.接受、发送数据 bufferevent_read()/bufferevent_write()
9.启动循环监听
10.释放资源
2.服务器端代码实现
#include<event2/listener.h>
#include<event2/bufferevent.h>
#include<event2/event.h>
#include<sys/epoll.h>
#include<sys/select.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
#include<string.h>
#include<dirent.h>
#include<sys/stat.h>
#include<wait.h>
#include<sys/mman.h>
#include<signal.h>
#include<pthread.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<ctype.h>
#include<strings.h>
#include<netinet/ip.h>
#define SERV_PORT 9527
//读回调
void read_cb(struct bufferevent *bev,void *arg)
{
char buf[1024]={0};
//替代的是read函数
bufferevent_read(bev,buf,sizeof(buf));
printf("client say:%s\n",buf);
char *p="我是服务器,已经成功收到你发送的数据";
//写数据给客户端 替代write函数
bufferevent_write(bev,p,strlen(p)+1);
sleep(1);
}
//写缓冲区的回调函数比较鸡肋,写缓冲区有数据就自动写给客户端了,写完了才会进行回调
void write_cb(struct bufferevent *bev,void *arg)
{
//printf("我是服务器,已经成功写数据给客户端,写缓冲区回调函数被回调");
}
//事件回调
void event_cb(struct bufferevent *bev,short events,void *arg)
{
//读到末尾
if(events & BEV_EVENT_EOF)
printf("连接关闭");
//发生错误
else if(events&BEV_EVENT_ERROR)
printf("other error");
bufferevent_free(bev);
printf("buffevent 资源已经被释放..\n");
}
void cb_listener(
struct evconnlistener *listener,
evutil_socket_t fd,//服务器cfd用于连接的文件描述符
struct sockaddr *addr,//客户端的地址结构
int len,void *ptr)
{
printf("connect new client\n");
//将最开始创建的libevent的框架用ptr传入赋值给base
struct event_base *base=(struct event_base *)ptr;
//添加新事件
struct bufferevent *bev;
bev=bufferevent_socket_new(base,fd,BEV_OPT_CLOSE_ON_FREE);
//给bufevent的读写缓冲区设置回调函数
bufferevent_setcb(bev,read_cb,write_cb,event_cb,NULL);
//启用bufferevent的读缓冲区,写缓冲区默认是enable的
bufferevent_enable(bev,EV_READ);
}
int main(int argc,char * argv[])
{
//初始化服务器套接字
struct sockaddr_in serv;
memset(&serv,0,sizeof(serv));
serv.sin_family=AF_INET;
serv.sin_port=htons(SERV_PORT);
serv.sin_addr.s_addr=htonl(INADDR_ANY);
//创建event_base
struct event_base* base;
base=event_base_new();
//创建监听器
struct evconnlistener *listener;
//参数3设置base
listener=evconnlistener_new_bind(base,cb_listener,base,
LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,36,//最大连接数量
(struct sockaddr *)&serv,sizeof(serv));
//启动循环监听
event_base_dispatch(base);
//释放和销毁
evconnlistener_free(listener);
event_base_free(base);
return 0;
}
运行结果:
3.客户端实现流程
1.创建 event_base
2.使用 bufferevnet_socket_new()创建一个用跟服务器通信的 bufferevnet 事件对象+
3.使用 bufferevnet_socket_connect()连接 服务器
4.使用 bufferevent_setcb()给 bufferevnet 对象的 read、write、event 设置回调
5.设置 bufferevnet 对象的读写缓冲区 enable/disable
6.接受、发送数据 bufferevent_read()/bufferevent_write()
7.释放资源
4.客户端代码实现
#include<event2/listener.h>
#include<event2/bufferevent.h>
#include<event2/event.h>
#include<sys/epoll.h>
#include<sys/select.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
#include<string.h>
#include<dirent.h>
#include<sys/stat.h>
#include<wait.h>
#include<sys/mman.h>
#include<signal.h>
#include<pthread.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<ctype.h>
#include<strings.h>
#include<netinet/ip.h>
#define SERV_PORT 9527
void read_cb(struct bufferevent *bev, void *arg)
{
char buf[1024] = {0};
bufferevent_read(bev, buf, sizeof(buf));
printf("fwq say:%s\n", buf);
bufferevent_write(bev, buf, strlen(buf)+1);
sleep(1);
}
void write_cb(struct bufferevent *bev, void *arg)
{
// printf("----------我是客户端的写回调函数,没卵用\n");
}
void event_cb(struct 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");
}
else if(events & BEV_EVENT_CONNECTED)
{
printf("已经连接服务器...\\(^o^)/...\n");
return;
}
// 释放资源
bufferevent_free(bev);
}
//从终端读然后写给服务器
void read_terminal(evutil_socket_t fd,short what,void *arg)
{
//读数据
char buf[1024]={0};
int len=read(fd,buf,sizeof(buf));
struct bufferevent *bev=(struct bufferevent*)arg;
//发送数据写给服务器
bufferevent_write(bev,buf,len+1);
}
int main(int argc,char * argv[])
{
struct event_base * base=NULL;
base=event_base_new();
//通信用的文件描述符
int fd=socket(AF_INET,SOCK_STREAM,0);
//fd封装到buffevent里面
struct bufferevent *bev=NULL;
bev=bufferevent_socket_new(base,fd,BEV_OPT_CLOSE_ON_FREE);
struct sockaddr_in serv;
memset(&serv,0,sizeof(serv));
serv.sin_family=AF_INET;
serv.sin_port=htons(9527);
inet_pton(AF_INET,"127.0.0.1",&serv.sin_addr.s_addr);
//连接服务器
bufferevent_socket_connect(bev,(struct sockaddr*)&serv,
sizeof(serv));
//设置回调函数
bufferevent_setcb(bev,read_cb,write_cb,event_cb,NULL);
//设置读回调生效
bufferevent_enable(bev,EV_READ);
//创建事件 从键盘读入客户端写入的内容 加入到base里面一起监听
struct event*ev=event_new(base,STDIN_FILENO,EV_READ|EV_PERSIST,read_terminal,bev);
//添加事件到监听
event_add(ev,NULL);
event_base_dispatch(base);
event_free(ev);
event_base_free(base);
return 0;
}
运行结果: