Posted on 2014-02-12 07:36:22 c
libev是Marc Lehmann用C写的高性能事件循环库。通过libev,可以灵活地把各种事件组织管理起来,如:时钟、io、信号等。libev在业界内也是广受好评,不少项目都采用它来做底层的事件循环。
libev所实现的功能就是一个强大的reactor,可以notify的事件主要包括下面这些:
watcher是Reactor中的Event Handler。一方面,它向事件循环提供了统一的调用接口(按类型区分);另一方面,它是外部代码的注入口,维护着具体的watcher信息,如:绑定的回调函数,watcher的优先级,是否激活等。
ev_io的主要使命就是监听并响应指定文件描述fd上的读写事件。对fd的监听工作,主要委托给底层的io库来完成。libev对目前比较流行的io库都提供了支持,如:select, epoll以及windows的iocp等。在这里libev使用了Adaptor模式,通过统一的适配层隐藏了底层io库的细节。
ev_timer是主要负责处理超时事件的watcher。这类watcher被存储在loop->timers中,它们的特点是,超时时间小的watcher会被先触发。
ev_prepare 在事件循环发生阻塞前会被触发。
ev_check 在事件循环阻塞结束后会被触发。ev_check的触发是按优先级划分的。可以保证,ev_check是同一个优先级上阻塞结束后最先被触发的watcher。所以,如果要保证ev_check是最先被执行的,可以把它的优先级设成最高。
ev_io和ev_timer应该是libev中使用的最多的watcher了,也是比较典型的watcher。
获取标准输入:
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);
创建一个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);
创建一个小时为单位的周期定时器:
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);
在收到 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);
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);
}
监控/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);
#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);
}
Propecia Hair
Baclofene Posologie Vidal Plaquenil Mwoiyj
how long before cialis kicks in cialis discount card
levitra drugstore levitra dosage how long does it last https://xclevitradb.com/
levitra onset of action levitra effect duration https://glevitrargu.com/
when will cialis become generic wholesale cialis https://dccialisxvf.com/
essay on earthquake in english save water save life essay 200 words in hindi https://essayrightversion.com/
female viagra pharmacy sildenafil tablets 50mg buy https://viagrause5.com/
fish mox amoxicillin buy amoxil 500mg canada el amoxil 400mg para que sirve amoxicillin capsules 500mg
generic viagra professional 100mg where to buy female viagra uk order viagra online no prescription https://zenviagrok.com/