libevent 编程流程

libevent 是一个基于reactor的模型,本事是个同步的,底层封装了select/epoll ,通过循环检测,如果有就绪事件,通知处理函数处理。

libevent 编程逻辑

  1. 调用event_init  创建event_base,一个event_base 相当于一个reactor实例
  2. 然后给这个实例创建具体的注册方法:
    // 创建新事件
        struct event *event_new(
            struct event_base *base, // reactor 实例
            evutil_socket_t fd, - // 文件描述符 - int  **底层是对epollin与epollout的封装**
            short what, 
            event_callback_fn cb, // 事件的处理回调函数
            void *arg //回调函数传参
    ); 

     short  what 事件标志:

    EV_TIMEOUT
    这个标志表示某超时时间流逝后事件成为激活的。构造事件的时候,EV_TIMEOUT 标志是
    被忽略的:可以在添加事件的时候设置超时,也可以不设置。超时发生时,回调函数的 what
    参数将带有这个标志。
    
    EV_READ
    表示指定的文件描述符已经就绪,可以读取的时候,事件将成为激活的。
    
    EV_WRITE
    表示指定的文件描述符已经就绪,可以写入的时候,事件将成为激活的。
    
    EV_SIGNAL
    用于实现信号检测,请看下面的“构造信号事件”节。
    
    EV_PERSIST
    表示事件是“持久的”,请看下面的“关于事件持久性”节。
    
    EV_ET
    表示如果底层的 event_base 后端支持边沿触发事件,则事件应该是边沿触发的。这个标志
    影响 EV_READ 和 EV_WRITE 的语义。

     

  3. event_add()将事件添加到event_base 上
    // event_add
        int event_add(
                    struct event *ev, 
                    const struct timeval *tv
                    ); 
    - tv:参数    Value
    NULL:    事件被触发, 对应的回调被调用
    tv = {0, n}    设置的时间,在改时间段内检测的事件没被触发, 时间到达之后, 回调函数还是会被调用

     

  4. 使用event_base_dispatch()函数 事件循环

  5. 释放资源
    // 创建event_free
        void event_free(struct event *event); 
    // 释放event_base_free
    event_base_free(struct event_base* base);

     

一个http使用libevent:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<event.h>
#include<fcntl.h>
#define PATH   "/home/liuchen/"
#define MAX 100

struct event* map_arr[MAX];
void Map_arr_init()
{
  int i=0;
  for(;i<MAX;i++)
  {
    map_arr[i]=NULL;
  }
}

void Map_arr_add(int fd,struct event* ev)
{
  if(fd<0||fd>MAX)
  {
    return;
  }
  map_arr[fd]=ev;
}
struct event* Map_arr_find(int fd)
{
  if(fd<0||fd>MAX)
  {
    return NULL;
  }
  return map_arr[fd];
}
int Sockfd_create()
{
  int sockfd=socket(AF_INET,SOCK_STREAM,0);
  if(sockfd==-1)
  {
    return -1;
  }
  struct sockaddr_in saddr;
  memset(&saddr,0,sizeof(saddr));
  saddr.sin_family = AF_INET;
  saddr.sin_port = htons(80);
  saddr.sin_addr.s_addr = inet_addr("0.0.0.0");

  int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
  if(res==-1)
  {
    return -1;
  }
  if(listen(sockfd,5))
  {
    return -1;
  }
  return sockfd;
}
void Recv_cb(int fd,short ev,void *arg)
{
  struct sockaddr_in * caddr = (struct sockaddr_in*)arg;
  if(ev & EV_READ)
  {

    char buff[1024]={0};
    int n=recv(fd,buff,1023,0);
    if(n<=0)
    {
      event_free(Map_arr_find(fd));
      map_arr[fd]=NULL;
      close(fd);
      printf("one client over id=%s  port=%d",inet_ntoa(caddr->sin_addr),ntohs(caddr->sin_port));
      return;
    }
    char *pname=NULL;
    pname=strtok(buff," ");
    if(pname==NULL)
    {
      event_free(Map_arr_find(fd));
      map_arr[fd]=NULL;
      close(fd);
      return;
    }
    printf("Method:%s\n",pname);

    char *filename=strtok(NULL," ");
    if(filename==NULL)
    {
      event_free(Map_arr_find(fd));
      map_arr[fd]=NULL;
      close(fd);
      return;
    }

    char path[128]={PATH};
       if ( strcmp(filename,"/") == 0 )
        {
            strcat(path,"/index.html");
        }
        else
        {
            strcat(path,filename);
        }

        int xd = open(path,O_RDONLY);
        if(xd==-1)
        {
           event_free(Map_arr_find(fd));
           map_arr[fd]=NULL;
           close(fd);
           return;
        }
        int filesize = lseek(xd,0,SEEK_END);
        lseek(xd,0,SEEK_SET);
        char head_buff[256] = {"HTTP/1.1 200 OK\r\n"};
        strcat(head_buff,"Server: myhttp\r\n");
        sprintf(head_buff+strlen(head_buff),"Content-Length: %d\r\n",filesize);
        strcat(head_buff,"\r\n");
        printf("send:\n%s\n",head_buff);
        send(fd,head_buff,strlen(head_buff),0);
        char data[512] = {0};
        int num = 0;
        while( (num = read(xd,data,512)) > 0 )
        {
            send(fd,data,num,0);
    
        }
  }
}
void accept_cb(int fd,short ev,void *arg)
{
  struct event_base * base=(struct event_base*)arg;
  if(ev & EV_READ)
  {
    struct sockaddr_in caddr;
    socklen_t len=sizeof(caddr);
    int c=accept(fd,(struct sockaddr*)&caddr,&len);
    if(c<0)
    {
      return;
    }
    struct event* ev_c = event_new(base,c,EV_READ | EV_PERSIST,Recv_cb,&caddr);
    event_add(ev_c,NULL);
    Map_arr_add(c,ev_c);
  }
}
int main()
{
  Map_arr_init();
  int sockfd=Sockfd_create();
  assert(sockfd!=-1);

  struct event_base * base=event_base_new();
  assert(base!=NULL);

  struct event* sock_ev = event_new(base,sockfd,EV_READ | EV_PERSIST,accept_cb,(void *)base);
  event_add(sock_ev,NULL);
  event_base_dispatch(base);
  event_free(sock_ev);
  event_base_free(base);

}

 

posted @ 2020-03-01 14:50  睡觉lc  阅读(520)  评论(0)    收藏  举报