• libevent库bufferevent事件实现socket通信


    一、基础API

    1. 添加 bufferevent 事件

    struct bufferevent *bufferevent_socket_new(struct event_base *base, 
    					evutil_socket_t fd, 
    					enum bufferevent_options options);
    
    • 1
    • 2
    • 3

    base: event_base
    fd: 封装bufferevent内的 通信文件描述符fd
    options:BEV_OPT_CLOSE_ON_FREE (释放资源)
    成功:bufferevent 指针; 失败:NULL

    2. 给读写缓冲区设置回调

    void bufferevent_setcb(struct bufferevent *bufev,
    				bufferevent_data_cb readcb,
    				bufferevent_data_cb writecb,
    				bufferevent_event_cb eventcb,
    				void *cbarg);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    bufev: bufferevent_socket_new() 返回值
    readcb: 设置 bufferevent 读缓冲,对应回调 read_cb() { bufferevent_read() 读数据 }
    writecb: 设置 bufferevent 写缓冲,对应回调 write_cb(){ 给调用者,发送写成功通知} (可传 NULL)
    eventcb: 设置 事件回调。 (可传NULL)
    cbarg: 上述回调函数使用的 参数

    读回调函数原型:

    typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *cbarg);
    
    void read_cb(struct bufferevent *bev, void *cbarg )
    {
    		.....
    		bufferevent_read();   //read()不能使用,用其替代
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    bufferevent_read() 函数原型:

    size_t bufferevent_read(struct bufferevent *bev, void *buf, size_t bufsize);
    
    • 1

    写回调函数原型:

    void write_cb(struct bufferevent *bev, void *cbarg);
    
    • 1

    bufferevent_write() 函数原型:

    int bufferevent_write(struct bufferevent *bufev, const void *data,  size_t size); 
    
    • 1

    event 回调函数原型:

    typedef void (*bufferevent_event_cb)(struct bufferevent *bev,  short events, void *cbarg);
    
    void event_cb(struct bufferevent *bev,  short events, void *cbarg)
    {
    	......
    }
    
    events: BEV_EVENT_CONNECTED (连接客户端成功事件标志)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3. 启动、关闭 bufferevent 的缓冲区

    默认、write 缓冲区开启、read 缓冲区关闭

    启动 :

    void bufferevent_enable(struct bufferevent *bufev, short events);   
    
    • 1

    关闭:

    void bufferevent_diable(struct bufferevent *bufev, short events);   
    
    • 1

    events: EV_READ、EV_WRITE、EV_READ|EV_WRITE

    short bufferevent_get_enabled(struct bufferevent *bufev);
    获取缓冲区的状态,需要借助 & 来得到
    
    • 1
    • 2

    4. 客户端连接服务器

    int bufferevent_socket_connect(struct bufferevent *bev, 
    				struct sockaddr *address, int addrlen);
    
    • 1
    • 2

    address、len: connect() 参2/3

    5. 服务端创建监听器

    struct evconnlistener *evconnlistener_new_bind (	
    				struct event_base *base,
    				evconnlistener_cb cb, 
    				void *ptr, 
    				unsigned flags,
    				int backlog,
    				const struct sockaddr *sa,
    				int socklen);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    base: event_base
    cb: 回调函数。 一旦被回调,说明在其内部应该与客户端完成, 数据读写操作,进行通信
    ptr: 回调函数的参数
    flags: LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE
    backlog: listen() 2参。 -1 表最大值
    sa:服务器自己的地址结构体
    socklen:服务器自己的地址结构体大小
    返回值:成功创建的监听器

    typedef void (*evconnlistener_cb)(
    				struct evconnlistener *listener,
    				evutil_socket_t sock,
    				struct sockaddr *addr,
    				int len,
    				void *ptr);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    listener: evconnlistener_new_bind 函数返回值
    sock: 用于通信的文件描述符
    addr: 客户端的 IP+端口
    len: addr的长度
    ptr:外部 ptr 传递进来的值

    二、bufferevent 事件开发框架

    服务器端:

    1. 创建event_base :event_base_new()
    2. 创建监听服务器, 设置其监听回调函数,当有客户端成功连接时,这个回调函数会被调用 :evconnlistener_new_bind()
    3. 监听服务器回调函数 listener_cb() 内部 添加bufferevent事件 实现通信 :bufferevent_socket_new()
    4. bufferevent事件的 read、write、event 事件设置回调函数:bufferevent_setcb()
    5. 设置读缓冲、写缓冲的 使能状态: bufferevent_enable()
    6. 启动事件循环 event_base_dispatch()
    7. 释放资源

    客户端

    1. 创建event_base
    2. 创建bufferevent事件
    3. 使用bufferevnet_socket_connect()连接服务器
    4. bufferevent事件的 read、write、event 事件设置回调函数
    5. 设置读缓冲、写缓冲的 使能状态
    6. 接受、发送数据 bufferevent_read() / bufferevent_write()
    7. 启动事件循环 event_base_dispatch()
    8. 释放资源

    三、示例

    服务端:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <event2/event.h>
    #include <event2/bufferevent.h>
    #include <event2/listener.h>
    
    #define PROT 8888
    
    void write_cb(struct bufferevent *bev, void *cbarg)
    {
    	printf("send successful...\n");
    }
    
    void read_cb(struct bufferevent *bev, void *cbarg)
    {
    	char buf[128] = {0};
    
    	bufferevent_read(bev, buf, sizeof(buf));
    	fputs(buf, stdout);
    	bufferevent_write(bev, "Data received successfully\n", 32);
    }
    
    void event_cb(struct bufferevent *bev, short events, void *cbarg)
    {
    	//其他事件 处理
    }
    
    void cb_listener(
    		struct evconnlistener *listener,
    		evutil_socket_t fd,
    		struct sockaddr *addr,
    		int len, void *base)
    {
    	//添加bufferevent事件 绑定通信描述符 进行通信
    	struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    
    	// 给bufferevent缓冲区设置回调函数 
    	bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);
    	//读缓冲区使能
    	bufferevent_enable(bev, EV_READ);
    }
    
    int main(void)
    {
    	//客户端地址结构
    	struct sockaddr_in caddr;
    	caddr.sin_family = AF_INET;
    	caddr.sin_port   = htons(PROT);
    	caddr.sin_addr.s_addr = htonl(INADDR_ANY);
    	//创建event_base
    	struct event_base *base = event_base_new();	
    	//创建监听服务器
    	struct evconnlistener *listener = evconnlistener_new_bind(base, cb_listener, base,
    			BEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
    			-1, (struct sockaddr*)&caddr, sizeof(caddr));
    
    	event_base_dispatch(base);
    
    	evconnlistener_free(listener);
    	event_base_free(base);
    
    	return 0;
    }
    
    • 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

    客户端:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>
    #include <event2/event.h>
    #include <event2/bufferevent.h>
    #include <event2/listener.h>
    
    #define PROT 8888
    
    void write_cb(struct bufferevent *bev, void *cbarg)
    {
    	printf("send successful...\n");
    }
    
    void read_cb(struct bufferevent *bev, void *cbarg)
    {
    	char buf[128] = {0};
    
    	bufferevent_read(bev, buf, sizeof(buf));
    	fputs(buf, stdout);
    }
    
    void event_cb(struct bufferevent *bev, short events, void *cbarg)
    {
    	//
    }
    
    void read_terminal(evutil_socket_t fd, short what, void *cbarg)
    {
    	char buf[128] = {0};
    	struct bufferevent *bev = (struct bufferevent*)cbarg;	
    	//将标准输入写到服务器
    	int len = read(STDIN_FILENO, buf, sizeof(buf));	
    	bufferevent_write(bev, buf, len);
    }
    
    int main(void)
    {
    	//服务器地址结构
    	struct sockaddr_in caddr;
    	caddr.sin_family = AF_INET;
    	caddr.sin_port   = htons(PROT);
    	inet_pton(AF_INET, "127.0.0.1", &caddr.sin_addr);
    	
    	int fd = socket(AF_INET, SOCK_STREAM, 0);		
    	
    	struct event_base *base = event_base_new();	
    	//添加 bufferevent 事件 绑定通信文件描述符 进行通信
    	struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    	//连接到服务器	
    	bufferevent_socket_connect(bev, (struct sockaddr*)&caddr, sizeof(caddr));	
    	//设置回调函数
    	bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);	
    	//使能读缓冲区
    	bufferevent_enable(bev, EV_READ);
    	//添加 event事件 读标准输入并写到服务器
    	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;
    }
    
    • 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
  • 相关阅读:
    C#实现钉钉自定义机器人发送群消息帮助类
    Spring:常用注解总结(持续更新~~~)
    国际经济学名词解释
    路西德Lucid EDI项目测试流程
    Hydra工具的使用
    医学专题(6)--多组学在肿瘤分型研究中的应用思路
    数据库的新选择 Amazon Aurora
    EL表达式中的常量与变量
    python性能分析
    上手Python之列表
  • 原文地址:https://blog.csdn.net/weixin_54178481/article/details/125602057