pselect偶尔会被打断

时间:2013-05-15 12:42:31

标签: c sockets select udp

首先,我没有声称将此标记为关于'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 */
}

现在,上述情况在绝大多数案例中都很好(尽管我可能会错误地输入一些内容,因为我无法访问复制/粘贴)。然而,pselect确实会返回-1,并且strerror(errno)调用打印“Interrupted system call”。

我甚至不确定这是你想要进行套接字超时的方式,我甚至不记得我是如何想出这个解决方案......

非常感谢任何帮助。

2 个答案:

答案 0 :(得分: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 */
}

答案 1 :(得分:0)

不,真的,只需重启系统调用即可。如果再次失败,则表示您的进程收到了另一个信号。据我所知,EINTR主要是来自早期Unix系统的实现工具,因此它们可以在阻止系统调用进行的同时传递信号。关于它是一个聪明的还是一个愚蠢的设计决定,已经有很多墨水了,但结果就是当调用失败并EINTR时,阻塞系统调用的代码需要重试。