Linux下编译libevent的指导可以参考《4、《Libevent中文帮助文档》学习笔记4:Linux下编译libevent》,完成编译、安装,生成so库后,其他程序即可依赖libevent的so库,使用libevent的功能。
由于没有通过prefix指定安装路径,因此库文件默认安装在/usr/local/lib下,头文件在/usr/local/include下,如下所示:
如图可以看出,libevent的so库存在软链接现象。
集成libevent的源码如下:
/*For sockaddr_in*/
#include <netinet/in.h>
/*For socket functions*/
#include <sys/socket.h>
/*For fcntl*/
#include <fcntl.h>
#include <event2/event.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#define MAX_LINE 16384void do_read(evutil_socket_t fd, short events, void*arg);
void do_write(evutil_socket_t fd, short events, void*arg);char rot13_char(char c)
{/* We don’t want to use isalpha here; setting the locale change which characters are considered alphabetical.*/if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M')){return c + 13;}else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z')){return c - 13;}else{return c;}
}struct fd_state
{char buffer[MAX_LINE];size_t buffer_used;size_t n_written;size_t write_upto;struct event* read_event;struct event* write_event;
};struct fd_state* alloc_fd_state(struct event_base* base, evutil_socket_t fd)
{struct fd_state* state = malloc(sizeof(struct fd_state));if (!state) return NULL;state->read_event = event_new(base, fd, EV_READ | EV_PERSIST, do_read, state);if (!state->read_event){free(state); return NULL;}state->write_event = event_new(base, fd, EV_WRITE | EV_PERSIST, do_write, state);if (!state->write_event){event_free(state->read_event);free(state);return NULL;}state->buffer_used = state->n_written = state->write_upto = 0;assert(state->write_event);return state;
}void free_fd_state(struct fd_state* state)
{event_free(state->read_event);event_free(state->write_event);free(state);
}void do_read(evutil_socket_t fd, short events, void*arg)
{struct fd_state*state = arg;char buf[1024]; int i; ssize_t result;while (1){assert(state->write_event);result = recv(fd, buf, sizeof(buf), 0);if(result <= 0)break;for (i = 0; i < result; ++i){if (state->buffer_used < sizeof(state->buffer))state->buffer[state->buffer_used++] = rot13_char(buf[i]);if (buf[i] == '\n'){assert(state->write_event);event_add(state->write_event, NULL);state->write_upto = state->buffer_used;}}}if (result == 0){free_fd_state(state);}else if (result < 0){if (errno == EAGAIN) // XXXX use evutil macro return ; perror("recv"); free_fd_state(state);}
} void do_write(evutil_socket_t fd, short events, void*arg)
{struct fd_state*state = arg;while (state->n_written < state->write_upto){ssize_t result = send(fd, state->buffer + state->n_written, state ->write_upto - state->n_written, 0);if (result < 0){if (errno == EAGAIN) // XXX use evutil macro return ;free_fd_state(state);return;}assert(result != 0);state->n_written += result;}if (state->n_written == state->buffer_used)state->n_written = state->write_upto = state->buffer_used = 1;event_del(state->write_event);
}void do_accept(evutil_socket_t listener, short event, void*arg)
{struct event_base*base = arg;struct sockaddr_storage ss;socklen_t slen =sizeof(ss);int fd = accept(listener, (struct sockaddr*) &ss, &slen);if (fd < 0){// XXXX eagain??perror("accept");}else if (fd > FD_SETSIZE){close(fd); // XXX replace all closes with EVUTIL_CLOSESOCKET}else{struct fd_state*state;evutil_make_socket_nonblocking(fd);state =alloc_fd_state(base, fd);assert(state);/*XXX err */assert(state->write_event);event_add(state->read_event, NULL);}
}void run(void)
{struct event_base* base = event_base_new();if (!base) return;/* 创建socket */struct sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_addr.s_addr = 0;sin.sin_port = htons(40713);evutil_socket_t listener = socket(AF_INET, SOCK_STREAM, 0);/* 设置为非阻塞 */evutil_make_socket_nonblocking(listener);#ifndef WIN32{int one = 1;setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));}
#endif/* 绑定socket */if (bind(listener, (struct sockaddr*) &sin, sizeof(sin)) < 0){perror("bind");return;}/* 启动监听 */if (listen(listener, 16) < 0){perror("listen");return;}struct event* listener_event = event_new(base, listener, EV_READ | EV_PERSIST, do_accept,(void*)base);/*XXX check it*/event_add(listener_event, NULL);event_base_dispatch(base);
}int main(int c, char**v)
{setvbuf(stdout, NULL, _IONBF, 0);run();return 0;
}
编写完源码后,接下去的工作就是编译。使用如下命令进行编译:
gcc -o server server.c -levent_core
由于libevent安装在/usr/local/lib目录下,因为不需要指定依赖路径,直接指定依赖libevent_core.so即可。
编译成功后,执行如下命令,运行可执行文件sever:
./server
出现如下报错:
./server: error while loading shared libraries: libevent_core-2.1.so.6: cannot open shared object file: No such file or directory
即无法加载可执行文件server的依赖库libevent_core-2.1.so.6,看到这里有点懵了,编译时,指定的依赖库文件明明是libevent_core.so,为什么在这里变为libevent_core-2.1.so.6,猜想可能原因是-levent_core匹配到/usr/local/lib/目录下的libevent_core-2.1.so.6了。但是,无论是libevent_core-2.1.so.6,还是libevent_core.so,都只是一个文件软链接,最终指向的都是libevent_core-2.1.so.6.0.2。
即使server依赖的是libevent_core-2.1.so.6,但是为啥运行报错了?/usr/local/lib目录下是有这个文件的啊?因此,通过如下命令查看server的依赖库信息:
ldd server
依赖库如下所示:
linux-vdso.so.1 => (0x00007ffd4f78b000)
libevent_core-2.1.so.6 => not found
libc.so.6 => /lib64/libc.so.6 (0x00007fa2a92b5000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa2a9682000)
发现确实无法加载到libevent_core-2.1.so.6。通过如下命令,查看server的库搜索路径:
LD_DEBUG=libs ./server -v
搜索路径为:
20398: find library=libevent_core-2.1.so.6 [0]; searching
20398: search cache=/etc/ld.so.cache
20398: search path=/lib64/tls/x86_64:/lib64/tls:/lib64/x86_64:/lib64:/usr/lib64/tls/x86_64:/usr/lib64/tls:/usr/lib64/x86_64:/usr/lib64 (system search path)
20398: trying file=/lib64/tls/x86_64/libevent_core-2.1.so.6
20398: trying file=/lib64/tls/libevent_core-2.1.so.6
20398: trying file=/lib64/x86_64/libevent_core-2.1.so.6
20398: trying file=/lib64/libevent_core-2.1.so.6
20398: trying file=/usr/lib64/tls/x86_64/libevent_core-2.1.so.6
20398: trying file=/usr/lib64/tls/libevent_core-2.1.so.6
20398: trying file=/usr/lib64/x86_64/libevent_core-2.1.so.6
20398: trying file=/usr/lib64/libevent_core-2.1.so.6
20398:
./server: error while loading shared libraries: libevent_core-2.1.so.6: cannot open shared object file: No such file or directory
发现搜索路径中,并没有/usr/local/lib,自然是无法加载到libevent_core-2.1.so.6。因此,将libevent_core-2.1.so.6拷贝到搜索路径下即可。也可以通过如下命令,为/usr/local/lib/libevent_core-2.1.so.6在/usr/lib64/下创建一个软链接:
ln -s /usr/local/lib/libevent_core-2.1.so.6 /usr/lib64/libevent_core-2.1.so.6