Linux下libevent库的使用


在了解了libevent的安装后,再来了解一下它的使用,特别是进行多线程的使用。其实这个最大的好处就是他在内部帮你封装好了epoll/select多路复用,并且使用了一些设计模式(比如反应堆模式),用事件机制来简化了socket编程然后要用的时候直接把相应的文件描述符加进去即可!

1.libevent的好处

  1. 假设有N个客户端同时往服务端通过socket写数据,用了libevent之后,你的server程序里就不用再使用epoll或是select来判断都哪些socket的缓冲区里已经收到了客户端写来的数据。当某个socket的缓冲区里有可读数据时,libevent会自动触发一个“读事件”,通过这个“读事件”来调用相应的代码来读取socket缓冲区里的数据即可。换句话说,libevent自己调用select()或是epoll的函数来判断哪个缓冲区可读了,只要可读了,就自动调用相应的处理程序。
  2. 对于“写事件”,libevent会监控某个socket的缓冲区是否可写(一般情况下,只要缓冲区没满就可写),只要可写,就会触发“写事件”,通过“写事件”来调用相应的函数,将数据写到socket里。

2.libevent的使用

其实服务器端libevent的使用也就是几个步骤,通俗一点就算再创建了libevent对象之后把监听的socket加进去,然后进入事件循环就好了!那么具体来看看步骤:

(1). 首先我们必须了解socket的一般流程,然后socket、bind、listen,再设置为非阻塞模式。

(2). 创建一个event_base对象

//创建一个event_base
struct event_base *base = event_base_new();
assert(base != NULL);

struct event_base *base = event_base_new()用以创建一个事件处理的全局变量,可以理解为这是一个负责集中处理各种出入IO事件的总管家,它负责接收和派发所有输入输出IO事件的信息,这里调用的是函数event_base_new(), 很多程序里这里用的是event_init(),区别就是前者是线程安全的、而后者是非线程安全的,后者在其官方说明中已经被标志为过时的函数、且建议用前者代替,libevent中还有很多类似的函数,比如建议用event_base_dispatch代替event_dispatch,用event_assign代替event_set和event_base_set等,关于libevent接口的详细说明见其官方说明libevent_doc。

event_base内部有一个循环,循环阻塞在epoll/kqueue等系统调用上,直到有一个或者一些事件发生,然后去处理这些事件。当然,这些事件要被绑定在这个event_base上。每个事件对应一个struct event,可以是监听一个fd或者POSIX信号量之类。struct event使用event_new来创建和绑定,使用event_add来启用。

(3). 创建一个event对象,并且将其监听的socket托管给event_base,指定要监听的事件类型,并绑上相应的回调函数

//创建并绑定一个event
struct event *listen_event;
//参数:event_base, 监听的fd,事件类型及属性,绑定的回调函数,给回调函数的参数
listen_event = event_new(base, listener, EV_READ|EV_PERSIST, callback_func, (void*)base);

(4). 通过event_add方法启动监听事件

//参数:event,超时时间(struct timeval *类型的,NULL表示无超时设置)
event_add(listen_event, NULL);

(5). 进入事件循环
需要启动event_base的循环,这样才能开始处理发生的事件。循环的启动使用event_base_dispatch,循环将一直持续,直到不再有需要关注的事件,或者是遇到event_loopbreak()/event_loopexit()函数。
这里事件循环的好处就是写程序的时候就不用采用死循环(while(1)/for(; ;))方式去连接,因为这里会事件循环,有事情触发的时候便会调用相应的回调函数!

//启动事件循环
event_base_dispatch(base);

在执行完这5步之后大致的流程就走完了,然后连接上客户端之后在缓冲区调用wirte()/read()函数就可以发送和接收数据了。同时可以接收多个客户端的连接,因为epoll/selecet多路复用已经封装在libevent库里面了!

3.libevent编写多线程

libevent中多线程的编写最主要的一点就是创建多个base,可以采用在主线程里面创建一个base,然后当有客户端连接的时候就创建一个子线程,重新创建一个base,处理这个客户端的消息,接收或者发送数据。
但是这样写的话会有局限性,来一个客户端就创建线程,如果客户端很多的话,内存可能会崩溃,下面会接着学习处理这个问题。

在写程序之前我们可以养成一个习惯,先试着画一下流程图,它可以帮助你整理一下思路:
在这里插入图片描述

然后我贴一下代码:

   /*********************************************************************************
    *      Copyright:  (C) 2020 Juan
    *                  All rights reserved.
    *
    *       Filename:  G4module_server.c
    *    Description:  This file 
    *                 
    *        Version:  1.0.0(22/07/20)
    *         Author:  wangruijie <1046299465@qq.com>
   *      ChangeLog:  1, Release initial version on "22/07/20 03:09:18"
   *                 
   ********************************************************************************/
  #include"G4module_server.h"
  
  int main(int argc, char **argv)
  {
   
      int                    sockfd = -1;   //赋一个无关紧要的值
      int                    rv = -1;
      struct sockaddr_in     local_addr;   //网络地址结构体
      struct event_base*     base = event_base_new();   //用以创建一个事件处理的全局变量,可以理解为这是一个负责集中处理各种出入IO事件的总管家
      struct event           listen_ev;  //创建一个event对象
      int                    opt;
      char                   buf[1024];
      char                   *progname = NULL;
      int                    SERVER_PORT;
      struct sock_ev_write   *sock_ev_write_struct;
  
      struct option            long_options[]=
      {
   
          {
   "port", required_argument, NULL, 'p'},
          {
   "help", no_argument, NULL, 'h'},
          {
   NULL, 0, NULL, 0}
      };
  
      progname = basename(argv[0]);
  
      while((opt = getopt_long(argc,argv
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值