常规事件
server
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <event2/event.h>
void read_cb(evutil_socket_t fd, short what, void *arg) {
char buf[1024];
int len = read(fd, buf, sizeof(buf));
printf("%s \n", what & EV_READ ? "yes" : "no");
printf("%s %d \n", buf, len);
sleep(1);
}
int main() {
unlink("myfifo");
mkfifo("myfifo", 0664);
/**
* 获取读权限,设置非阻塞.
* 这里之所以非阻塞是因为libevent是基于事件异步的通行模型,主要异步执行回调函数.
*/
int fd = open("myfifo", O_RDONLY | O_NONBLOCK);
//创建event_base,类似于epoll红黑树根节点
struct event_base *base = event_base_new();
/**
* 创建事件
* fd表示绑定到 创建的ev 上的文件描述符
* EV_READ 一次读事件
* EV_WRITE 一次写事件
* EV_PERSIST 持续触发,需要结合event_base_dispatch使用,才生效.不指定,则只执行一次
* read_cb满足事件监听的回调函数
*
* void read_cb(evutil_socket_t fd, short what, void *arg)
* fd 对应这里的fd
* what 对应这里的EV_READ | EV_PERSIST
* arg 对应最后一个参数NULL
*/
struct event *ev = event_new(base, fd, EV_READ | EV_PERSIST, read_cb, NULL);
/**
* 添加一个[常规事件]到event_base
* timeout:设置超时时间
* NULL:不会超时,等到事件被触发,回调函数立刻执行
* 非0:期间检查事件有没有触发,一旦时间到则事件会被回调.
*/
event_add(ev, NULL);
/**
* 从event_base删除事件
*
*/
//event_del(ev);
//事件循环 可理解为while(1) epoll_wait()
event_base_dispatch(base);
//指定时间后停止
// event_base_loopexit()
//立即停止
// event_base_loopbreak()
//销毁添加的事件
event_free(ev);
//销毁event_base
event_base_free(base);
close(fd);
return 0;
}
client
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <event2/event.h>
void write_cb(evutil_socket_t fd, short what, void *arg) {
char buf[1024] = "hello";
static int num = 0;
sprintf(buf, "hello world %d\n", num++);
printf("%s", buf);
write(fd, buf, strlen(buf) + 1);
sleep(1);
}
int main() {
int fd = open("myfifo", O_WRONLY | O_NONBLOCK);
//创建event_base
struct event_base *base = event_base_new();
//创建事件
struct event *ev = event_new(base, fd, EV_WRITE | EV_PERSIST, write_cb, NULL);
//添加事件
event_add(ev, NULL);
//事件循环
event_base_dispatch(base);
//销毁添加的事件
event_free(ev);
//销毁event_base
event_base_free(base);
close(fd);
return 0;
}
缓冲事件
server
#include <sys/stat.h>
#include <string.h>
#include<event2/bufferevent.h>
#include <event2/event.h>
#include <event2/listener.h>
#define PORT 8080
/**
* 缓冲事件
* 有2个缓冲区,队列实现.
*/
void read_cb(struct bufferevent *bev, void *ctx) {
char buf[1024];
//从读缓存中读取数据
bufferevent_read(bev, buf, sizeof(buf));
printf("client say : %s \n", buf);
char *p = "world";
//向写缓存中写数据,一旦有数据就会自动刷新,发送给对端,发送成功后,会被通知写回调方法.
bufferevent_write(bev, p, strlen(p) + 1);
}
void write_cb(struct bufferevent *bev, void *ctx) {
printf("发送成功 \n");
}
/**
* 事件回调
* @param bev
*
* @param what
* 不同标志位,表示不同事件
BEV_EVENT_READING 读缓冲区满足,则产生事件
BEV_EVENT_WRITING 写缓冲区满足,则产生事件
BEV_EVENT_EOF 读到文件结尾
BEV_EVENT_ERROR 出错,则产生事件
BEV_EVENT_TIMEOUT 超时
BEV_EVENT_CONNECTED 请求的连接过程完成,客户端时可用
*
* @param ctx 回调函数参数
*/
void event_cb(struct bufferevent *bev, short what, void *ctx) {
if (what & BEV_EVENT_EOF) {
printf("connection closed \n");
} else if (what & BEV_EVENT_ERROR) {
printf("error \n");
}
bufferevent_free(bev);
printf("资源释放 \n");
}
/**
* 客户端连接后,回调
* @param listener 当调用evconnlistener_new_bind返回的监听器
* @param fd 客户端的套接字
* @param addr 客户端地址
* @param len 客户端地址长度
* @param ptr 当调用evconnlistener_new_bind设置的参数
*/
void cb_listener(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr, int len, void *ptr) {
struct event_base *base = (struct event_base *) ptr;
/**
* 创建bufferevent
* struct bufferevent *bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options);
* base event_base_new()返回值
* fd 跟bufferevent绑定的fd
* options
* BEV_OPT_CLOSE_ON_FREE:释放bufferevent时关闭底层传输端口,也就是关闭底层套接字,释放底层bufferevent等
*/
struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
// bufferevent_free() 释放缓冲事件
/**
* 给bufferevent设置回调
void bufferevent_setcb(struct bufferevent *bufev,
bufferevent_data_cb readcb, bufferevent_data_cb writecb,
bufferevent_event_cb eventcb, void *cbarg);
bufev : bufferevent_socket_new返回值
readcb :读回调,不用传NULL即可
writecb :写事件满足时回调
eventcb :事件回调
cbarg :回调函数所有参数
*
*/
bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);
/**
* 启用缓冲区
* 默认写缓冲是启用的,读缓冲没启用
*/
bufferevent_enable(bev, EV_READ);
//禁用缓冲区
// bufferevent_disable(bev, EV_READ);
//获取缓冲区禁用状态,可通过&判断
// bufferevent_get_enabled(bev);
}
int main() {
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
struct event_base *base = event_base_new();
/**
* 相当于socket,bind,listen,accept
* 创建套接字,绑定,接收连接请求
* struct evconnlistener *evconnlistener_new_bind(struct event_base *base,
evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
const struct sockaddr *sa, int socklen);
* base : event_base_new()返回值
* cb : 接受连接之后,回调函数
* ptr : 回调函数参数
* flags :
* LEV_OPT_CLOSE_ON_FREE 释放bufferevent时关闭底层传输端口,也就是关闭底层套接字,释放底层bufferevent等
* LEV_OPT_REUSEABLE 端口复用
* backlog : listen的第二个参数, -1表示默认最大值
* sa / socklen : 传给bind的参数 服务器的ip+port 以及长度
*/
struct evconnlistener *listener = evconnlistener_new_bind(base, cb_listener, base,
LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 36,
(struct sockaddr *) &serv_addr, sizeof(serv_addr));
event_base_dispatch(base);
evconnlistener_free(listener);
event_base_free(base);
return 0;
}
client
#include <string.h>
#include<event2/bufferevent.h>
#include <event2/event.h>
#include <arpa/inet.h>
#include <unistd.h>
#define PORT 8080
void read_cb(struct bufferevent *bev, void *ctx) {
char buf[1024];
bufferevent_read(bev, buf, sizeof(buf));
printf("server say : %s \n", buf);
bufferevent_write(bev, buf, strlen(buf) + 1);
sleep(1);
}
void write_cb(struct bufferevent *bev, void *ctx) {
printf("发送成功 \n");
}
void event_cb(struct bufferevent *bev, short what, void *ctx) {
if (what & BEV_EVENT_EOF) {
printf("connection closed \n");
} else if (what & BEV_EVENT_ERROR) {
printf("error \n");
} else if (what & BEV_EVENT_CONNECTED) {
printf("已经连接服务器 \n");
return;
}
bufferevent_free(bev);
printf("资源释放 \n");
}
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;
printf("terminal rev : %s \n", buf);
bufferevent_write(bev, buf, len + 1);
}
int main() {
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct event_base *base = event_base_new();
struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
/**
* int bufferevent_socket_connect(struct bufferevent *bufferevent, struct sockaddr * addr, int len);
* bufferevent 事件对象(封装了fd)
* addr / len 等同于connect的addr和len参数
*/
bufferevent_socket_connect(bev, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);
bufferevent_enable(bev, EV_READ);
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;
}