libev简介

Comments(50)


Posted on 2014-02-12 07:36:22 c


简介

libev是Marc Lehmann用C写的高性能事件循环库。通过libev,可以灵活地把各种事件组织管理起来,如:时钟、io、信号等。libev在业界内也是广受好评,不少项目都采用它来做底层的事件循环。

libev所实现的功能就是一个强大的reactor,可以notify的事件主要包括下面这些:

  • ev_io // IO可读可写
  • ev_stat // 文件属性变化
  • ev_async // 激活线程
  • ev_signal // 信号处理
  • ev_timer // 定时器
  • ev_periodic // 周期任务
  • ev_child // 子进程状态变化
  • ev_fork // 开辟进程
  • ev_cleanup // event loop退出触发事件
  • ev_idle // 每次event loop空闲触发事件
  • ev_embed // TODO:I have no idea.
  • ev_prepare // 每次event loop之前事件
  • ev_check // 每次event loop之后事件

Watcher介绍

watcher是Reactor中的Event Handler。一方面,它向事件循环提供了统一的调用接口(按类型区分);另一方面,它是外部代码的注入口,维护着具体的watcher信息,如:绑定的回调函数,watcher的优先级,是否激活等。

ev_io

ev_io的主要使命就是监听并响应指定文件描述fd上的读写事件。对fd的监听工作,主要委托给底层的io库来完成。libev对目前比较流行的io库都提供了支持,如:select, epoll以及windows的iocp等。在这里libev使用了Adaptor模式,通过统一的适配层隐藏了底层io库的细节。

ev_timer

ev_timer是主要负责处理超时事件的watcher。这类watcher被存储在loop->timers中,它们的特点是,超时时间小的watcher会被先触发。

ev_prepare

ev_prepare 在事件循环发生阻塞前会被触发。

ev_check

ev_check 在事件循环阻塞结束后会被触发。ev_check的触发是按优先级划分的。可以保证,ev_check是同一个优先级上阻塞结束后最先被触发的watcher。所以,如果要保证ev_check是最先被执行的,可以把它的优先级设成最高。

ev_io和ev_timer应该是libev中使用的最多的watcher了,也是比较典型的watcher。

Watcher示例代码:

ev_io

获取标准输入:

static void
stdin_readable_cb (struct ev_loop *loop, ev_io *w, int revents)
{
  ev_io_stop (loop, w);
  .. read from stdin here (or from w->fd) and handle any I/O errors
}

ev_io stdin_readable;
ev_io_init (&stdin_readable, stdin_readable_cb, STDIN_FILENO, EV_READ);
ev_io_start (loop, &stdin_readable);

ev_timer

创建一个60s之后启动的计时器:

static void
one_minute_cb (struct ev_loop *loop, ev_timer *w, int revents)
{
  .. one minute over, w is actually stopped right here
}

ev_timer mytimer;
ev_timer_init (&mytimer, one_minute_cb, 60., 0.);
ev_timer_start (loop, &mytimer);

创建一个10s超时的超时器:

static void
timeout_cb (struct ev_loop *loop, ev_timer *w, int revents)
{
  .. ten seconds without any activity
}

ev_timer mytimer;
ev_timer_init (&mytimer, timeout_cb, 0., 10.); /* note, only repeat used */
ev_timer_again (&mytimer); /* start timer */
ev_run (loop, 0);

// and in some piece of code that gets executed on any "activity":
// reset the timeout to start ticking again at 10 seconds
ev_timer_again (&mytimer);

ev_periodic

创建一个小时为单位的周期定时器:

static void
clock_cb (struct ev_loop *loop, ev_periodic *w, int revents)
{
  ... its now a full hour (UTC, or TAI or whatever your clock follows)
}

ev_periodic hourly_tick;
ev_periodic_init (&hourly_tick, clock_cb, 0., 3600., 0);
ev_periodic_start (loop, &hourly_tick);

或者自定义周期计算方式:

#include <math.h>

static ev_tstamp
my_scheduler_cb (ev_periodic *w, ev_tstamp now)
{
  return now + (3600. - fmod (now, 3600.));
}

ev_periodic_init (&hourly_tick, clock_cb, 0., 0., my_scheduler_cb);

如果想从当前时间开始:

ev_periodic hourly_tick;
ev_periodic_init (&hourly_tick, clock_cb,
                  fmod (ev_now (loop), 3600.), 3600., 0);
ev_periodic_start (loop, &hourly_tick);

ev_signal

在收到 SIGINT 时做些清理:

static void
sigint_cb (struct ev_loop *loop, ev_signal *w, int revents)
{
  ev_break (loop, EVBREAK_ALL);
}

ev_signal signal_watcher;
ev_signal_init (&signal_watcher, sigint_cb, SIGINT);
ev_signal_start (loop, &signal_watcher);

ev_child

fork 一个新进程,给它安装一个child处理器等待进程结束:

ev_child cw;

static void
child_cb (EV_P_ ev_child *w, int revents)
{
  ev_child_stop (EV_A_ w);
  printf ("process %d exited with status %x\n", w->rpid, w->rstatus);
}

pid_t pid = fork ();

if (pid < 0) {
  // error
}
else if (pid == 0)
  {
    // the forked child executes here
    exit (1);
  }
else
  {
    ev_child_init (&cw, child_cb, pid, 0);
    ev_child_start (EV_DEFAULT_ &cw);
  }

ev_stat

监控/etc/passwd是否有变化:

static void
passwd_cb (struct ev_loop *loop, ev_stat *w, int revents)
{
  /* /etc/passwd changed in some way */
  if (w->attr.st_nlink)
    {
      printf ("passwd current size  %ld\n", (long)w->attr.st_size);
      printf ("passwd current atime %ld\n", (long)w->attr.st_mtime);
      printf ("passwd current mtime %ld\n", (long)w->attr.st_mtime);
    }
  else
    /* you shalt not abuse printf for puts */
    puts ("wow, /etc/passwd is not there, expect problems. "
          "if this is windows, they already arrived\n");
}

...
ev_stat passwd;

ev_stat_init (&passwd, passwd_cb, "/etc/passwd", 0.);
ev_stat_start (loop, &passwd);

TCP Server代码

#include <stdio.h>
#include <netinet/in.h>
#include <ev.h>

#define PORT_NO 3033
#define BUFFER_SIZE 1024

int total_clients = 0;  // Total number of connected clients

void accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents);
void read_cb(struct ev_loop *loop, struct ev_io *watcher, int revents);

int main()
{
struct ev_loop *loop = ev_default_loop(0);
int sd;
struct sockaddr_in addr;
int addr_len = sizeof(addr);
struct ev_io w_accept;

// Create server socket
if( (sd = socket(PF_INET, SOCK_STREAM, 0)) < 0 )
{
  perror("socket error");
  return -1;
}

bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT_NO);
addr.sin_addr.s_addr = INADDR_ANY;

// Bind socket to address
if (bind(sd, (struct sockaddr*) &addr, sizeof(addr)) != 0)
{
  perror("bind error");
}

// Start listing on the socket
if (listen(sd, 2) < 0)
{
  perror("listen error");
  return -1;
}

// Initialize and start a watcher to accepts client requests
ev_io_init(&w_accept, accept_cb, sd, EV_READ);
ev_io_start(loop, &w_accept);

// Start infinite loop
while (1)
{
  ev_loop(loop, 0);
}

return 0;
}

/* Accept client requests */
void accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
{
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_sd;
struct ev_io *w_client = (struct ev_io*) malloc (sizeof(struct ev_io));

if(EV_ERROR & revents)
{
  perror("got invalid event");
  return;
}

// Accept client request
client_sd = accept(watcher->fd, (struct sockaddr *)&client_addr, &client_len);

if (client_sd < 0)
{
  perror("accept error");
  return;
}

total_clients ++; // Increment total_clients count
printf("Successfully connected with client.\n");
printf("%d client(s) connected.\n", total_clients);

// Initialize and start watcher to read client requests
ev_io_init(w_client, read_cb, client_sd, EV_READ);
ev_io_start(loop, w_client);
}

/* Read client message */
void read_cb(struct ev_loop *loop, struct ev_io *watcher, int revents){
char buffer[BUFFER_SIZE];
ssize_t read;

if(EV_ERROR & revents)
{
  perror("got invalid event");
  return;
}

// Receive message from client socket
read = recv(watcher->fd, buffer, BUFFER_SIZE, 0);

if(read < 0)
{
  perror("read error");
  return;
}

if(read == 0)
{
  // Stop and free watchet if client socket is closing
  ev_io_stop(loop,watcher);
  free(watcher);
  perror("peer might closing");
  total_clients --; // Decrement total_clients count
  printf("%d client(s) connected.\n", total_clients);
  return;
}
else
{
  printf("message:%s\n",buffer);
}

// Send message bach to the client
send(watcher->fd, buffer, read, 0);
bzero(buffer, read);
}
前一篇: fcntl的close-on-exec标志 后一篇: Greenlet简介

Captcha:
验证码

Email:

Content: (Support Markdown Syntax)


FiExhip  2022-12-26 01:47:24 From 127.0.0.1

How long for the immune system to recover after prednisone https://symbicortinhaler.com/ symbicort copay card


Oblisy  2023-01-20 16:34:19 From 127.0.0.1

Mother’s ruin, tiredness and solicitude can all pretend to your ability to tune in to or fence in an erection, so your playing can be affected every at once and then. But if it’s phenomenon oftentimes then it’s usefulness a smite to your GP so they can dominion in any tenable fitness issues. Source: cialis coupon discounts


Amberlyelmr  2023-02-17 19:40:52 From 127.0.0.1

single chat sites free dating site best online dating sites


muumbtty  2023-03-18 11:40:45 From 127.0.0.1

Король и Шут все серии https://bit.ly/kish-serial


Bruitamut  2023-05-18 18:42:07 From 127.0.0.1

Importantly, loss of a single kidney could not account for the rapid progressive loss of GFR developing over the several months before admission associated with a rise in creatinine from 1 cialis without prescription Metformin hydrochloride, USP N, N dimethyl monohydrochloride, Imidodicarbonimidic diamide is not chemically or pharmacologically related to any other classes of oral antihyperglycemic agents


dblLBSyi  2023-09-04 00:09:17 From 127.0.0.1

Debra Patt, MD, MPH, MBA what is the shelf life of viagra Some of the other possible causes of anemia include


Ernestlag  2023-11-30 18:04:33 From 127.0.0.1

hi! I enjoyed your article, thank you very much! allonezaimy.ru


GeorgeBoype  2024-01-25 11:30:53 From 127.0.0.1

https://rybnoe.net/forum/16-12455-1


CharlesJab  2024-01-29 19:35:35 From 127.0.0.1

https://synthesit-shop.ru/ - Синтезит железо


mohamedsalahaz  2024-09-21 22:46:16 From 127.0.0.1

salah 2021 2022 http://mohamed-salah-az.com/ barcelona real madrid 11 0 mohamed salah az com .