对于libevent的知识一点不了解,通知编写测试代码,发现问题,解决问题,一步一步入门学习。
CMakeLists.txt文件:
project(libevent_project)
cmake_minimum_required(VERSION 3.8)
message(STATUS "lkmao:CMAKE_SOURCE_DIR -- ${CMAKE_SOURCE_DIR}")
set(LIBEVET_INSTALL_PATH "/big/libevent/libevent-2.1.12-stable/_install/")
include_directories(
${LIBEVET_INSTALL_PATH}/include
)
# set(CMAKE_C_COMPILER /arm-gcc/bin/arm-linux-gnueabihf-gcc)
# set(CMAKE_CXX_COMPILER /arm-gcc/bin/arm-linux-gnueabihf-g++)
# SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -pthread")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread -lstdc++")
message(STATUS "lkmao:PROJECT_SOURCE_DIR -- ${PROJECT_SOURCE_DIR}")
# add_executable(main_01 main_01.c)
# target_link_libraries(main_01 ${LIBEVET_INSTALL_PATH}/lib/libevent.so)
add_executable(app main_02.c)
target_link_libraries(app ${LIBEVET_INSTALL_PATH}/lib/libevent.so)
编译脚本文件build.sh:
#!/bin/bash
set -e
rm -rf _build_
mkdir _build_ -p
cmake -S ./ -B _build_
make -C _build_
# ./_build_/main_01
./_build_/app
源码文件main_02.c
源码:
#include <sys/types.h>
#include <event2/event-config.h>
#include <stdio.h>
#include <event.h>
#include <stdlib.h>
#include <unistd.h>
#define _DEBUG_INFO
#ifdef _DEBUG_INFO
#define DEBUG_INFO(format, ...) printf("%s:%d $$ " format "\n" \
,__func__,__LINE__ \
, ##__VA_ARGS__)
#else
#define DEBUG_INFO(format, ...)
#endif
struct private_data{
struct event ev;
struct timeval tv;
struct event_base *base;
char buffer[1024];
};
void stdin_callback(int fd, short event, void *argc)
{
struct private_data *p = (struct private_data *)argc;
memset(p->buffer, 0, sizeof(p->buffer));
read(fd,p->buffer,sizeof(p->buffer));
DEBUG_INFO("buffer = %s",p->buffer);
event_add(&p->ev, &p->tv);
}
int main(int main,char *argv[])
{
struct private_data *p = malloc(sizeof(struct private_data));
p->base = event_init();
p->tv.tv_sec = 100;
p->tv.tv_usec = 0;
event_set(&p->ev, STDIN_FILENO, EV_READ, stdin_callback,p);
event_base_set(p->base, &p->ev);
event_add(&p->ev, &p->tv);
event_base_dispatch(p->base);
}
执行结果:
实验解析:
输入hello然后回车,看到stdin_callback函数被调用,在stdin_callback中调用read,读取标准输入中的数据,并将数据打印到标准输出。
关键代码解析
event_set(&p->ev, STDIN_FILENO, EV_READ, timer_cb,p);
STDIN_FILENO:标准输入文件描述符,就是0
EV_READ:读事件,写事件是EV_WRITE
设置阻塞模式
前例中设置的是100秒超时,大部分情况下,我们需要没有数据就绪的时候,处于长久等待模式,就是阻塞模式,测试代码如下:
#include <sys/types.h>
#include <event2/event-config.h>
#include <stdio.h>
#include <event.h>
#include <stdlib.h>
#include <unistd.h>
#define _DEBUG_INFO
#ifdef _DEBUG_INFO
#define DEBUG_INFO(format, ...) printf("%s:%d $$ " format "\n" \
,__func__,__LINE__ \
, ##__VA_ARGS__)
#else
#define DEBUG_INFO(format, ...)
#endif
struct private_data{
struct event ev;
struct event_base *base;
char buffer[1024];
};
void stdin_callback(int fd, short event, void *argc)
{
struct private_data *p = (struct private_data *)argc;
memset(p->buffer, 0, sizeof(p->buffer));
read(fd,p->buffer,sizeof(p->buffer));
DEBUG_INFO("buffer = %s",p->buffer);
event_add(&p->ev, NULL);
}
int main(int main,char *argv[])
{
struct private_data *p = malloc(sizeof(struct private_data));
p->base = event_init();
//p->ev.ev_base->flags |= EV_BLOCK;
event_set(&p->ev, STDIN_FILENO, EV_READ, stdin_callback,p);
event_base_set(p->base, &p->ev);
event_add(&p->ev, NULL);
event_base_dispatch(p->base);
}
执行结果
实验解析:
相比前例,删除了struct timeval tv;将出现tv的地方使用NULL代替即可。
在多线程中使用
源码:
#include <sys/types.h>
#include <event2/event-config.h>
#include <stdio.h>
#include <event.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define _DEBUG_INFO
#ifdef _DEBUG_INFO
#define DEBUG_INFO(format, ...) printf("%s:%d $$ " format "\n" \
,__func__,__LINE__ \
, ##__VA_ARGS__)
#else
#define DEBUG_INFO(format, ...)
#endif
struct private_data{
struct event ev;
char buffer[1024];
};
struct event_base *base = NULL;
void stdin_callback(int fd, short event, void *argc)
{
struct private_data *p = (struct private_data *)argc;
memset(p->buffer, 0, sizeof(p->buffer));
read(fd,p->buffer,sizeof(p->buffer));
DEBUG_INFO("buffer = %s",p->buffer);
event_add(&p->ev, NULL);
}
void* add_fd_thread(void *arg){
while(base == NULL){
sleep(1);
}
struct private_data *p = malloc(sizeof(struct private_data));
event_set(&p->ev, STDIN_FILENO, EV_READ, stdin_callback,p);
event_base_set(base, &p->ev);
event_add(&p->ev, NULL);
while(1){
sleep(1);
}
return NULL;
}
void *run_thread(void *arg){
int res = 0;
base = event_init();
DEBUG_INFO("start");
do{
res = event_base_dispatch(base);
if(res < 0){
perror("event_base_dispatch");
DEBUG_INFO("res = %d", res);
exit(-1);
}
DEBUG_INFO("res = %d",res);
}while(1);
DEBUG_INFO("end");
return NULL;
}
int main(int main,char *argv[])
{
pthread_t t1,t2;
int res = 0;
res = pthread_create(&t1,NULL,add_fd_thread,NULL);
if(res < 0){
perror("1:pthread_create");
return -1;
}
res = pthread_create(&t2,NULL,run_thread,NULL);
if(res < 0){
perror("2:pthread_create");
return -1;
}
while(1){
sleep(1);
}
DEBUG_INFO("bye bye");
return 0;
}
测试结果:
在没有将事件添加到base中时,event_base_dispatch一直返回1。这肯定不是我们想要的效果。
在多线程中增加信号事件
#include <sys/types.h>
#include <event2/event-config.h>
#include <stdio.h>
#include <event.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <signal.h>
#define _DEBUG_INFO
#ifdef _DEBUG_INFO
#define DEBUG_INFO(format, ...) printf("%s:%d $$ " format "\n" \
,__func__,__LINE__ \
, ##__VA_ARGS__)
#else
#define DEBUG_INFO(format, ...)
#endif
struct private_data{
struct event ev;
char buffer[1024];
};
struct event_base *base = NULL;
void stdin_callback(int fd, short event, void *argc)
{
struct private_data *p = (struct private_data *)argc;
memset(p->buffer, 0, sizeof(p->buffer));
read(fd,p->buffer,sizeof(p->buffer));
DEBUG_INFO("buffer = %s",p->buffer);
event_add(&p->ev, NULL);
}
void* add_fd_thread(void *arg){
while(base == NULL){
sleep(1);
}
struct private_data *p = malloc(sizeof(struct private_data));
event_set(&p->ev, STDIN_FILENO, EV_READ, stdin_callback,p);
event_base_set(base, &p->ev);
event_add(&p->ev, NULL);
return NULL;
}
static void
signal_cb(evutil_socket_t sig, short events, void *user_data)
{
struct event_base *base = user_data;
struct timeval delay = { 2, 0 };
printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");
event_base_loopexit(base, &delay);
}
void *run_thread(void *arg){
int res = 0;
struct event *signal_event;
base = event_init();
signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);
if (!signal_event || event_add(signal_event, NULL)<0) {
fprintf(stderr, "Could not create/add a signal event!\n");
return 1;
}
DEBUG_INFO("start");
do{
res = event_base_dispatch(base);
if(res < 0){
perror("event_base_dispatch");
DEBUG_INFO("res = %d", res);
exit(-1);
}
DEBUG_INFO("res = %d",res);
}while(0);
event_free(signal_event);
event_base_free(base);
base = NULL;
DEBUG_INFO("end");
return NULL;
}
int main(int main,char *argv[])
{
pthread_t t1,t2;
int res = 0;
res = pthread_create(&t1,NULL,add_fd_thread,NULL);
if(res < 0){
perror("1:pthread_create");
return -1;
}
res = pthread_create(&t2,NULL,run_thread,NULL);
if(res < 0){
perror("2:pthread_create");
return -1;
}
sleep(1);
while(1){
sleep(1);
if(base == NULL){
break;
}
}
DEBUG_INFO("bye bye");
return 0;
}
执行结果:
实验解析
添加SIGINT事件后,base中监听的事件不为空了,所以它就不会返回了。按下CTRL+C后signal_cb函数被调用,延时两秒后,event_base_dispatch循环返回,返回值为0。当前的知识储备还不知道返回0和返回1的区别,但是至少代码运行看起来是正常了。