2013-04-06 49 views
0

我有興趣收聽傳入連接,並且當沒有活動連接時我想執行後臺處理。 我還沒有找到這兩個在一起的任何例子。一起使用libev ev_io和ev_idle事件

我想要做類似這樣的:

從一個例子:

//ev_io callback 

static void server_cb(EV_P_ ev_io *w, int revents) 
{ 
    //Accept new client connection 
    //Read from client socket 

    //stop event loop 
    ev_io_stop(EV_A_ &client->io); 

    //send back to client 

    //start event loop again 
    ev_io_start(EV_A_ &client->io); 

} 

main() 
{ 
    // To be sure that we aren't actually blocking 
    ev_periodic_init(&every_few_seconds, not_blocked, 0, 5, 0); 
    ev_periodic_start(EV_A_ &every_few_seconds); 

    // Get notified whenever the socket is ready to read 
    ev_io_init(&server.io, server_cb, server.fd, EV_READ); 
    ev_io_start(EV_A_ &server.io); 

} 
在這個例子中,我應該在哪裏添加空閒事件和在何地何時應該啓動和停止

現在空閒事件,以便它不會干擾主事件處理程序,只有在空閒時才應該調用它。

謝謝。

+0

這個傢伙有什麼? – user1621776 2013-04-10 08:58:23

回答

1

嗯,我也是libev的新手,但我把這個簡單的服務器演示了一個接收套接字數據的服務器,同時處理超時和空閒事件。

#include <ev.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 

static struct ev_loop *loop; 
static ev_timer timeout_watcher; 
static ev_io in_watcher; 
static ev_idle idle_watcher; 
static int sock_fd; 

// socket input watcher 
static void in_cb(EV_P_ ev_io *watcher, int revents) { 
    int r, t; 
    char buf[1024]; 
    for (t = 0; (r = read(sock_fd, buf, sizeof(buf))) > 0;) { 
     t += r; 
     write(STDOUT_FILENO, buf, r); // copy input to stdout 
     if (buf[r-1] == '\n') break; // operate line-at-a-time 
    } 
    fprintf(stderr, "in: count = %d\n", t); 
    if (r == 0) { 
     fputs("in: connection closed\n", stderr); 
     ev_io_stop(loop, &in_watcher); // stop the socket watcher 
     ev_break(loop, EVBREAK_ALL); // exit the loop 
    } else if (r < 0) { 
     perror("read"); 
    } 
} 

static void timeout_cb(EV_P_ ev_timer *watcher, int revents) { 
    fprintf(stderr, "timeout: now = %f\n", ev_now(loop)); 
} 

static void idle_cb(EV_P_ ev_idle *watcher, int revents) { 
    static long idle_count = 0; 
    fprintf(stderr, "idle: count = %ld\n", ++idle_count); 
    sleep(1); // simulate doing stuff 
} 

int main() { 

    extern int errno; 

    int master_fd; 
    int sock_opt = 1; 
    int conn_port = 7000; 
    struct sockaddr_in addr; 
    socklen_t addrlen; 

    // **** the following is needed to set up a socket to receive data **** 
    master_fd = socket(AF_INET, SOCK_STREAM, 0); 
    if (master_fd == -1) { 
     perror("socket"); 
     return errno; 
    } 
    if (setsockopt(master_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &sock_opt, sizeof(sock_opt)) == -1) { 
     perror("setsockopt"); 
     return errno; 
    } 
    addr.sin_family = AF_INET; 
    addr.sin_addr.s_addr = INADDR_ANY; 
    addr.sin_port = htons(conn_port); 
    addrlen = sizeof(addr); 
    if (bind(master_fd, (struct sockaddr *) &addr, addrlen) != 0) { 
     perror("bind"); 
     return errno; 
    } 
    if (listen(master_fd, 3) != 0) { 
     perror("listen"); 
     return errno; 
    } 

    fprintf(stderr, "awaiting a connection on port %d\n", conn_port); 
    sock_fd = accept(master_fd, (struct sockaddr *) &addr, &addrlen); 
    if (sock_fd == -1) { 
     perror("accept"); 
     return errno; 
    } 
    fputs("in: connection established\n", stderr); 
    // **** end of socket setup code **** 

    // define a loop 
    loop = ev_default_loop(0); 

    // define a repeating timer 
    ev_timer_init (&timeout_watcher, timeout_cb, 5.0, 5.0); 
    ev_timer_start (loop, &timeout_watcher); 

    // define an idle process 
    ev_idle_init(&idle_watcher, idle_cb); 
    ev_idle_start (loop, &idle_watcher); 

    // define the socket data receiver 
    ev_io_init(&in_watcher, in_cb, sock_fd, EV_READ); 
    ev_io_start (loop, &in_watcher); 

    // run the loop 
    ev_run(loop, 0); 

    // clean up 
    close(sock_fd); 
    close(master_fd); 
    return 0; 
} 
0

您應該在調用用於進入主循環的ev_loop()之前添加ev_idle。 (實際上,你可以將它添加到任何你想要的地方,但對於上面的情況,我認爲沒關係)。

只有在沒有其他事件掛起時纔會調用你與空閒監視器綁定的回調。它不會干擾任何其他事件的回調。回調將被順序調用。

順便說一下,我建議你在libev中小心使用閒置事件。 因爲如果你不控制它,它會消耗整個CPU。 週期性事件會更好。 如果你想使用它(例如在計算密集型程序中),最好在一次回調中做一件小事。這樣它會將控制權放回主循環以迴應其他事件。 (例如,io事件)

PS:您不必在server_cb回調中調用ev_io_stop並再次調用ev_io_start。 因爲回調不會受到任何干擾。