<span style="font-size:18px;">1,要使用libevent首先需要安装了,安装地址http://libevent.org/,我选着的1.4稳定版本的了,安装过程就是常用linux安装的3步而已</span>
<span style="font-size:18px;">2,在使用libevent之前,了解一下常用的并发服务器的模型还是有必要的基于事件触发的库,<a target=_blank href="http://blog.csdn.net/sun734274006/article/details/41897487" style="color: rgb(0, 0, 0); text-decoration: none; font-family: 'Microsoft YaHei'; line-height: 30px;">常见多线程与并发服务器设计方案举例</a></span>
<span style="font-size:18px;">3,代码+解释</span>
<pre name="code" class="cpp"><span style="font-size:24px;">/* * Compile with: * cc -I/usr/local/include -o event-test event-test.c -L/usr/local/lib -levent */ #include <sys/types.h> #include <sys/stat.h> #include <sys/queue.h> #include <unistd.h> #include <sys/time.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <event.h> #define PORT 54321 #define BACKLOG 20 #define MEM_SIZE 1024 struct event_base* base; /*其实就是reactor(反应堆),可以形象的比喻为一个总管理,管理所有提供服务的服务者*/ struct sock_ev { struct event* read_ev; struct event* write_ev; char* buffer; }; //这是为了能够完全整体的释放内存,以前是这样写的, //如果客户端关闭size==0时候,write_ev,没有得到释放,导致内存泄漏,其实我觉得不用这样封装结构体也可以的,但是封装结构体过后感觉更加面向对象的了的感觉 //void on_read(int sock, short event, void* arg){ //struct event* write_ev; // int size; // char* buffer = (char*)malloc(MEM_SIZE); // bzero(buffer, MEM_SIZE); // size = recv(sock, buffer, MEM_SIZE, 0); // printf("receive data:%s, size:%d\n", buffer, size); // if (size == 0) { // event_del((struct event*)arg); // free((struct event*)arg); // close(sock); // return; // // } // write_ev = (struct event*) malloc(sizeof(struct event));; // event_set(write_ev, sock, EV_WRITE, on_write, buffer); // event_base_set(base, write_ev); // event_add(write_ev, NULL); //} void release_sock_event(struct sock_ev* ev) { event_del(ev->read_ev); free(ev->read_ev); free(ev->write_ev); free(ev->buffer); free(ev); } void on_write(int sock, short event, void* arg) { char* buffer = (char*)arg; send(sock, buffer, strlen(buffer), 0); //注意这里需要释放,是在on_read里面malloc的 free(buffer); } void on_read(int sock, short event, void* arg) { int size; struct sock_ev* ev = (struct sock_ev*)arg; ev->buffer = (char*)malloc(MEM_SIZE); bzero(ev->buffer, MEM_SIZE); size = recv(sock, ev->buffer, MEM_SIZE, 0); printf("receive data:%s, size:%d\n", ev->buffer, size); //当从socket读返回0标志对方已经关闭了连接,因此这个时候就没必要继续监听该套接口上的事件, //由于EV_READ在on_accept函数里是用EV_PERSIST(持久)参数注册的,因此要显示的调用event_del函数取消对该事件的监听。 if (size == 0) { release_sock_event(ev); close(sock); return; } event_set(ev->write_ev, sock, EV_WRITE, on_write, ev->buffer); event_base_set(base, ev->write_ev); event_add(ev->write_ev, NULL); } void on_accept(int sock, short event, void* arg) { struct sockaddr_in cli_addr; int newfd, sin_size; //这里必须要malloc,因为这个事件最后是要base里面的,如果是栈中分配,这个函数执行接受过后,变量的值被回收过后,在"后面"工作的base,将对一个空的操作,那样会crash struct sock_ev* ev = (struct sock_ev*)malloc(sizeof(struct sock_ev)); ev->read_ev = (struct event*)malloc(sizeof(struct event)); ev->write_ev = (struct event*)malloc(sizeof(struct event)); sin_size = sizeof(struct sockaddr_in); newfd = accept(sock, (struct sockaddr*)&cli_addr, &sin_size); //这里就是,监听这个sock,是否是可读,如果可以折触发on_read函数了,当然这里的event_set函数是系统补推荐的,建议使用event_assign函数具体可以看文档 event_set(ev->read_ev, newfd, EV_READ | EV_PERSIST, on_read, ev); event_base_set(base, ev->read_ev); event_add(ev->read_ev, NULL); } int main(int argc, char* argv[]) { struct sockaddr_in my_addr; int sock; sock = socket(AF_INET, SOCK_STREAM, 0); int yes = 1; //这是是需要注意一下,我们在编程的时候,有时候不小心我们使用的文件句柄, //资源没有释放,而程序有挂了当我们再次使用的时候,就会出线xxxx被用,这里SO_REUSEADDR,就是让他可以重复利用,具体的看以参考<UNP> setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); //下面这几行就是长用的步骤啦 memset(&my_addr, 0, sizeof(my_addr)); my_addr.sin_family = AF_INET; my_addr.sin_port = htons(PORT); my_addr.sin_addr.s_addr = INADDR_ANY; bind(sock, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)); listen(sock, BACKLOG); struct event listen_ev; /*它就是直接提供服务的,它呗 base管理*/ base = event_base_new(); //将我们监听的sock,绑定在listen_ev,即使让listen_ev帮我们管理,我们之处理,请求的到来,请求到来了将触发on_accept函数 event_set(&listen_ev, sock, EV_READ | EV_PERSIST, on_accept, NULL); event_base_set(base, &listen_ev); event_add(&listen_ev, NULL); //循环调用,就像服务器要一直运行吧,一旦有新的请求过来或者请求的I/O时候会调用处理 event_base_dispatch(base); return 0; }</span>
</pre><pre name="code" class="cpp">
时间: 2024-10-18 03:31:55