2013-12-12 53 views
0

我是libevent和socket編程的新手,這就是爲什麼我有關於libevent如何作爲異步和非阻塞工作的問題。 以下是參考代碼。 https://github.com/libevent/libevent/blob/master/sample/http-server.c在C編程中用libevent編寫非阻塞事件

static void dump_request_cb(struct evhttp_request *req, void *arg) 
{ 
    const char *cmdtype; 
    struct evkeyvalq *headers; 
    struct evkeyval *header; 
    struct evbuffer *buf; 

    printf("Request Start\n"); 
    sleep(30); // delay to read request to check non blocking event. 

    switch (evhttp_request_get_command(req)) { 
    case EVHTTP_REQ_GET: cmdtype = "GET"; break; 
    case EVHTTP_REQ_POST: cmdtype = "POST"; break; 
    case EVHTTP_REQ_HEAD: cmdtype = "HEAD"; break; 
    case EVHTTP_REQ_PUT: cmdtype = "PUT"; break; 
    case EVHTTP_REQ_DELETE: cmdtype = "DELETE"; break; 
    case EVHTTP_REQ_OPTIONS: cmdtype = "OPTIONS"; break; 
    case EVHTTP_REQ_TRACE: cmdtype = "TRACE"; break; 
    case EVHTTP_REQ_CONNECT: cmdtype = "CONNECT"; break; 
    case EVHTTP_REQ_PATCH: cmdtype = "PATCH"; break; 
    default: cmdtype = "unknown"; break; 
    } 

    printf("Received a %s request for %s\nHeaders:\n", 
     cmdtype, evhttp_request_get_uri(req)); 

    headers = evhttp_request_get_input_headers(req); 

    for (header = headers->tqh_first; header; 
     header = header->next.tqe_next) { 
      printf(" %s: %s\n", header->key, header->value); 
    } 
    buf = evhttp_request_get_input_buffer(req); 

    puts("Input data: <<<"); 

    while (evbuffer_get_length(buf)) { 
      int n; 
      char cbuf[128]; 
      n = evbuffer_remove(buf, cbuf, sizeof(cbuf)); 
      if (n > 0) 
        (void) fwrite(cbuf, 1, n, stdout); 
    } 
    puts(">>>"); 

    evhttp_send_reply(req, 200, "OK", NULL); 
} 

我創建的在上述請求30秒的延遲。

當我從瀏覽器發送兩個請求。代碼應該立即開始一次提供兩個請求。但這沒有發生。真正的情況是,第二次請求在第一次請求完成之後以30秒的延遲進行服務。這意味着總共需要60秒來處理兩個請求。

所以任何人都可以告訴我它是如何工作的non_blocking。

+0

我不知道'libevent',但我懷疑你混合'非阻塞'與'並行' – MeNa

+0

我開始網絡編程與libevent因爲它說你不需要線程,它是非阻塞異步套接字讀取。但我無法執行它。此外,我沒有找到任何好的例子在網絡上用libevent編寫非阻塞代碼。 – Vikas

+0

您可以使用循環和非阻塞套接字來獲得異步服務器(性能糟糕),但是當您** sleep()**系統時 - 循環再次被阻塞!你必須並行! – MeNa

回答

1

sleep(30) 打電話給你發,阻塞,libevent的沒有做任何魔法,以防止從執行阻塞調用。
您需要小心並且只使用非阻塞API。在這種情況下,你想延遲30秒的響應,這麼簡單,你可以使用libevent的evtimer_add()。但是這個原則適用於任何你想使用的API,你必須以非阻塞的方式使用它們(文件讀取,對其他服務器的調用,DB訪問等)。

+0

我對evtime_add()一無所知,但我也會對此做出解釋。在這我們可以推翻事件嗎? – Vikas

0

謝謝您的友好建議。

我使用線程概念並按照以下方式並行化事件,完成了非阻塞套接字。

void *newThread(void *arg){ 
printf("Before thread start\n"); 
struct evhttp_request *req; 
req = (struct evhttp_request *)arg; 
sleep(30); 
evhttp_send_reply(req, 200, "OK", NULL); 
printf("After thread end\n"); 
} 

static void dump_request_cb(struct evhttp_request *req, void *arg) 
{ 
const char *cmdtype; 
struct evkeyvalq *headers; 
struct evkeyval *header; 
struct evbuffer *buf; 

printf("Request Start\n"); 
sleep(30); // delay to read request to check non blocking event. 

switch (evhttp_request_get_command(req)) { 
case EVHTTP_REQ_GET: cmdtype = "GET"; break; 
case EVHTTP_REQ_POST: cmdtype = "POST"; break; 
case EVHTTP_REQ_HEAD: cmdtype = "HEAD"; break; 
case EVHTTP_REQ_PUT: cmdtype = "PUT"; break; 
case EVHTTP_REQ_DELETE: cmdtype = "DELETE"; break; 
case EVHTTP_REQ_OPTIONS: cmdtype = "OPTIONS"; break; 
case EVHTTP_REQ_TRACE: cmdtype = "TRACE"; break; 
case EVHTTP_REQ_CONNECT: cmdtype = "CONNECT"; break; 
case EVHTTP_REQ_PATCH: cmdtype = "PATCH"; break; 
default: cmdtype = "unknown"; break; 
} 

printf("Received a %s request for %s\nHeaders:\n", 
    cmdtype, evhttp_request_get_uri(req)); 

headers = evhttp_request_get_input_headers(req); 

for (header = headers->tqh_first; header; 
    header = header->next.tqe_next) { 
     printf(" %s: %s\n", header->key, header->value); 
} 
buf = evhttp_request_get_input_buffer(req); 

puts("Input data: <<<"); 

while (evbuffer_get_length(buf)) { 
     int n; 
     char cbuf[128]; 
     n = evbuffer_remove(buf, cbuf, sizeof(cbuf)); 
     if (n > 0) 
       (void) fwrite(cbuf, 1, n, stdout); 
} 
puts(">>>"); 
} 

即使有睡眠延遲,客戶端的每個請求都會與以前的請求並行。 我在libevent模塊中找不到任何解決方案,並使用替代線程概念完成了我的任務。