2013-05-15 31 views
0

首先和formost,我沒有把這個標記爲'pselect'的問題,所以我選擇了'select'。pselect被正式中斷

我使用pselect來處理UDP套接字上的超時。代碼如下所示:

UDP_STATUS udp_socket_recv(udp_socket_t* p_sock, int* p_bytes_rcvd) 
{ 
    int res = 0; 
    fd_set fds; 
    struct timespec timeout; 

    FD_ZERO(&fds); 
    FD_SET(p_sock->m_socket, &fds); 

    if (p_sock->m_timeout == NULL) { 
     res = pselect(p_sock->m_socket + 1, &fds, NULL, NULL, NULL, NULL); 
    } else { 
     timeout.tv_sec = p_sock->m_timeout->tv_sec; 
     timeout.tv_msec = p_sock->m_timeout->tv_usec * 1000; 
     res = pselect(p_sock->m_socket + 1, &fds, NULL, NULL, &timeout, NULL); 
    } 

    if (res == 0) 
     return UDP_TIMEOUT; 
    else if (res == -1) { 
     printf("pselect error: %s\n", strerror(errno)); /* Sometimes we end up here */ 
     return UDP_FAILURE; 
    } 

    res = recvfrom(p_sock->m_socket, ..); /* etc etc */ 
} 

現在,上面的作品只是在案件絕大多數罰款(雖然我可能misstyped的東西,因爲我沒有獲得複製/粘貼)。但是,pselect有時會返回-1,而strerror(errno)調用會打印「中斷的系統調用」。

我甚至不知道這是你想怎麼辦插座超時,我可以不記得我是怎麼想出了這個解決方案...

任何幫助深表感謝。

+1

那麼,這只是一箇中斷的系統調用。再次調用pselect(),mybe它會成功。順便說一下'if(p_sock-> m_timeout == NULL){'如果超時值爲NULL,則只調用pselect。您可能還想在'else {...}'情況下調用pselect()。 – wildplasser

+0

是的,我很抱歉,我忘記了else子句中的pselect。 關於再次調用pselect,如果再次失敗會怎麼樣? – user1986698

回答

2

EINTR/中斷的系統調用不是一個錯誤狀態,只是當你的程序在系統調用中被阻塞時發生了一些事情(信號被傳遞並可能被處理)。你可以忽略它,只是循環,就像這裏:(下面的程序是不是最佳的,只有你能如何處理EINTR示範)

UDP_STATUS udp_socket_recv(udp_socket_t* p_sock, int* p_bytes_rcvd) 
{ 
int res = 0; 
fd_set fds; 
struct timespec timeout; 

FD_ZERO(&fds); 
FD_SET(p_sock->m_socket, &fds); 

while(1) { 
    if (p_sock->m_timeout == NULL) { 
     res = pselect(p_sock->m_socket + 1, &fds, NULL, NULL, NULL, NULL); 
    } else { 
     timeout.tv_sec = p_sock->m_timeout->tv_sec; 
     timeout.tv_msec = p_sock->m_timeout->tv_usec * 1000; 
     res = pselect(p_sock->m_socket + 1, &fds, NULL, NULL, &timeout, NULL); 
    } 

    if (res > 0) break; 
    if (res == 0) 
    return UDP_TIMEOUT; 

    switch(errno) { 
    case EINTR: continue; 
    default: 
    printf("pselect error: %s\n", strerror(errno)); /* Sometimes we end up here */ 
    return UDP_FAILURE; 
    } 
} 

res = recvfrom(p_sock->m_socket, ..); /* etc etc */ 
} 
+2

這不處理'EINTR'。 「EAGAIN」是一個非常不同的野獸;這意味着沒有數據準備好閱讀。 – tmyklebu

+0

爲您服務!謝謝。 (是的,我把他們混在一起了!) – wildplasser

+0

這個伎倆。非常感謝大家,這節省了我的一天(甚至一週)。 :) – user1986698

0

不,真的,只需重新啓動系統調用。如果再次失敗,這意味着您的過程收到另一個信號。據我所知,EINTR很大程度上是早期Unix系統的一種實現方式,因此它們可以在阻止系統調用進行的同時傳遞信號。大量的墨水已經溢出,這是否是一個聰明或愚蠢的設計決定,但其結果是,代碼阻止系統調用需要重試,當調用失敗EINTR