libev入门

引言

实现应用的捷径是充分利用开放源代码和开放标准等资源。为了实现视频服务器,研究了开源视频服务器DarwinStreamingServer,Reactor并发编程设计模式,同时还评估了Boost.Asio、ACE、libevent以及 libev等网络编程相关的库。得出的结论是基于DarwinStreamingServer的设计思想,采用Reactor设计模式实现一个更加高效并可扩展的视频服务器,网络库则选择libev。

本文的目的是在理解libev的基础上,学习如何编写基于libev的应用程序。

libev是什么


要了解libev,有必要先了解libevent。早在2000年libevent就发布了第一个版本。通过libevent的编程接口,可以实现在指定的事件发生后调用回调函数,指定的事件是文件描述符上的读写事件等。除了文件描述符的事件,libevent还支持定时器以及信号等。欲详细了解libevent可以参照其站点:http://monkey.org/~provos/libevent/。

以下是libev站点上的自述:

A full-featured and high-performance event loop that is loosely modelled after libevent, but without its limitations and bugs. It is used, among others, in the GNU Virtual Private Ethernet and rxvt-unicode packages, and in the Deliantra MORPG Server and Client.

理解libev

Libev是一个event loop:向libev注册感兴趣的events,比如Socket可读事件,libev会对所注册的事件的源进行管理,并在事件发生时触发相应的程序。

To do this, it must take more or less complete control over your process (or thread) by executing the event loop handler, and will then communicate events via a callback mechanism.

通过event watcher来注册事件,which are relatively small C structures you initialise with the details of the event, and then hand it over to libev by starting the watcher.

先来解释watcher,libev通过分配和注册watcher对不同类型的事件进行监听。不同事件类型的watcher又对应不同的数据类型,watcher的定义模式是struct ev_TYPE或者ev_TYPE,其中TYPE为具体的类型。当前libev定义了如下类型的watcher:

  • ev_io
  • ev_timer
  • ev_periodic
  • ev_signal
  • ev_child
  • ev_stat
  • ev_idle
  • ev_prepare and ev_check
  • ev_embed
  • ev_fork
  • ev_cleanup
  • ev_async

下面是一个libev使用的例子,通过注册io类型的watcher来监视STDIN可读事件的发生:

   static void my_cb (struct ev_loop *loop, ev_io *w, int revents)
   {
     ev_io_stop (w);
     ev_break (loop, EVBREAK_ALL);
   }

   struct ev_loop *loop = ev_default_loop (0);

   ev_io stdin_watcher;,

   ev_init (&stdin_watcher, my_cb);
   ev_io_set (&stdin_watcher, STDIN_FILENO, EV_READ);
   ev_io_start (loop, &stdin_watcher);

   ev_run (loop, 0);

上面的示例代码中用到的与watcher相关的函数有ev_init,ev_io_set,ev_io_start,ev_io_stop。ev_init对一个watcher的与具体类型无关的部分进行初始化。ev_io_set对watcher的与io类型相关的部分进行初始化,显然如果是TYPE类型那么相应的函数就是ev_TYPE_set。可以采用ev_TYPE_init函数来替代ev_init和ev_TYPE_set。ev_io_start激活相应的watcher,watcher只有被激活的时候才能接收事件。ev_io_stop停止已经激活的watcher。

接下来看看event loop的概念。示例程序中的ev_run、ev_break以及ev_loop_default都是event loop控制函数。event loop定义为struct ev_loop。有两种类型的event loop,分别是default类型和dynamically created类型,区别是前者支持子进程事件。ev_default_loop和ev_loop_new函数分别用于创建default类型或者dynamically created类型的event loop。

event_run函数告诉系统应用程序开始对事件进行处理,有事件发生时就调用watcher callbacks。除非调用了ev_break或者不再有active的watcher,否则会一直重复这个过程。

libev编程

先来看libev提供的例子。这段代码等待键盘事件的发生,或者超时,两个事件都会触发程序结束。操作系统环境是ubuntu server 10.10,libev是下载的源码,并没有采用ubuntu server自己提供的版本,源码的地址是http://dist.schmorp.de/libev/libev-4.04.tar.gz。例子代码如下:

// 只需include一个头文件
#include <ev.h>
#include <stdio.h> // for puts

// every watcher type has its own typedef'd struct
// with the name ev_TYPE
ev_io stdin_watcher;
ev_timer timeout_watcher;

// all watcher callbacks have a similar signature
// this callback is called when data is readable on stdin
static void
stdin_cb (EV_P_ ev_io *w, int revents)
{
        puts ("stdin ready");
        // for one-shot events, one must manually stop the watcher
        // with its corresponding stop function.
        ev_io_stop (EV_A_ w);

        // this causes all nested ev_run's to stop iterating
        ev_break (EV_A_ EVBREAK_ALL);
}

// another callback, this time for a time-out
static void
timeout_cb (EV_P_ ev_timer *w, int revents)
{
        puts ("timeout");
        // this causes the innermost ev_run to stop iterating
        ev_break (EV_A_ EVBREAK_ONE);
}

int
main (void)
{
        // use the default event loop unless you have special needs
        struct ev_loop *loop = EV_DEFAULT;

        // initialise an io watcher, then start it
        // this one will watch for stdin to become readable
        ev_io_init (&stdin_watcher, stdin_cb, 0, EV_READ);
        ev_io_start (loop, &stdin_watcher);

        // initialise a timer watcher, then start it
        // simple non-repeating 5.5 second timeout
        ev_timer_init (&timeout_watcher, timeout_cb, 5.5, 0.);
        ev_timer_start (loop, &timeout_watcher);

        // now wait for events to arrive
        ev_run (loop, 0);

        // break was called, so exit
        return 0;
}

用如下命令编译:

gcc -lev -o sample sample.c


参考资料

  1. libev的文档
  2. http://software.schmorp.de/pkg/libev.html

你可能感兴趣的:(libev入门)