2013-05-15 2 views
0

첫 번째와 formost에서 'pselect'에 대한 질문으로 태그를 붙일 수있는 평판이 없었기 때문에 '선택'을 사용했습니다.pselect가 가끔씩 중단됩니다.

UDP 소켓에서 시간 초과를 처리하기 위해 pselect를 사용합니다. 코드는 다음과 같습니다

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 */ 
} 

이제, 케이스의 대부분에서 잘 위의 작품 (I 복사/붙여 넣기 할 수있는 권한이 없기 때문에 내가 뭔가를 잘못 입력했을 수도 있지만). 그러나 pselect는 때때로 strerror (errno) 호출로 "Interrupted system call"을 호출하여 -1을 반환합니다. 나는 이것이 내가 심지어 내가이 솔루션을 함께했다 방법을 기억할 수없는, 당신은 소켓 타임 아웃을하는 방법입니다 모르겠어요

...

어떤 도움이 많이 감사합니다.

+1

글쎄, 이것은 중단 된 시스템 호출 일뿐입니다. pselect()를 다시 호출하면 mybe가 이번에 성공할 것이다. BTW'if (p_sock-> m_timeout == NULL) {'timeout이 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은 내가 알고있는 한, 초기 유닉스 시스템의 구현 유물이기 때문에 시스템 호출을 차단하면서 신호를 전달할 수있다. 영리하거나 어리석은 디자인 결정인지 여부에 관계없이 많은 잉크가 쏟아져 나왔지만, 그 결과로 코드 호출을 막는 코드는 EINTR으로 실패 할 경우 다시 시도해야합니다.

관련 문제