4 处理连接 到这里为止,大家已经完成了事件的设置、事件的添加并进入到了事件循环。但是当事件发生时(这里就是连接建立)如何处理呢? 聪明的用户会想到前面我们在事件设置时指定的回调函数accept_handle。没错,当连接建立时回调函数accept_handle会自动的得到调用。 对于缓冲区的读写在非阻塞式网络编程中是一个难以处理的问题,幸运的是libevent提供了bufferevent和evbuf来替我们完成该项工作。这里我们采用bufferevent来处理。 (1)生成bufferevent对象 使用bufferevent_new对象来生成bufferevent对象,并分别指定读、写、连接错误时的处理函数和函数传入参数。 (2) 设置读取量 bufferevent的读事件激活以后,即使用户没有读取完bufferevent缓冲区中的数据, bufferevent读事件也不会再次被激活。因为bufferevent的读事件是由其所监控的描述符的读事件激活的,只有描述符可读,读事件才会被激活。可通过设置wm_read.high来控制bufferevent从描述符缓冲区中读取的数据量。 (3) 将事件加入事件队列 和前面一样,在事件设置好后,需将事件加入到事件队列中, 不过bufferevent的有自己专门的加入函数bufferevent_base_set和激活函数bufferevent_enable。 bufferevent接收两个参数事件根基个事件对象,前者用来指定事件将加入到哪个事件根基中,后者说明需将那个bufferevnet事件加入。(在多线程的情况下,每个线程可能有自己单独的事件根基) 在bufferevent初始化完毕后,可以使用bufferevent_enable和bufferevent_disable反复的激活与禁止事件,其接收参数为事件对象和事件标志。其中标志参数为EV_READ和EV_WRITE。 void accept_handle(const int sfd, const short event, void *arg){ struct sockaddr_in addr; socklen_t addrlen = sizeof(addr); int fd = accept(sfd, (struct sockaddr *) &addr, &addrlen); //处理连接 buf_ev = bufferevent_new(fd, buffered_on_read, NULL, NULL, fd) buf_ev->wm_read.high = 4096 bufferevent_base_set(main_base, buf_ev); bufferevent_enable(buf_ev, EV_READ); } 5 读取缓冲区 当缓冲区读就绪时会自动激活前面注册的缓冲区读函数,我们可以使用bufferevent_read函数来读取缓冲区 bufferevent_read函数参数分别为:所需读取的事件缓冲区,读入数据的存放地,希望读取的字节数。函数返回实际读取的字节数。 注意:及时缓冲区未读完,事件也不会再次被激活(除非再次有数据)。因此此处需反复读取直到全部读取完毕。 6 写回客户端 bufferevent系列函数不但支持读取缓冲区,而且支持写缓冲区(即将结果返回给客户端)。 void buffered_on_read(struct bufferevent *bev, void * arg){ char buffer[4096] ret = bufferevent_read(bev, &buffer, 4096); bufferevent_write(bef, (void *)&buffer, 4096); }
三 结束语 至此我们已经可以使用libevent编写非阻塞的事件驱动服务器,它支持连接建立、socket可读等事件的处理。 但在实际的使用事件驱动的服务器中,通常是使用一个线程处理连接,然后使用多个线程来处理请求。后面我将继续介绍如何使用libevent来编写多线程的服务器。 |
使用libevent编写linux服务(二)
最新推荐文章于 2020-10-13 17:47:50 发布
2009-08-22 17:42