Libevent实现TCP客户端服务器

17-libevent实现Tcp服务器流程_bilibili_哔哩哔哩_bilibili

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.服务器端代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#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;
}

运行结果:
image-20241217230949369

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.客户端代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#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;
}

运行结果:

image-20241217231300384