C socket recv()错误处理

时间:2013-04-16 14:06:08

标签: c

我对socket中的recv()函数有疑问(在linux Raspberri Pi上)

为什么我的程序停在:

if ((numbytes = recv(fd, odp, 100, 0)) == -1) {
    printf("\n error while test recv 1");
    perror("recv");
    reconnect = 1;
}

是的,有一个错误:“资源暂时不可用”

当我看到: printf("\n error while test recv 1");

我想要重新连接以后制作的内容。 但我在终端窗口看到我的程序停止了:

error while test recv 1

我试过了:

signal(SIGPIPE, SIG_IGN);

而不是:

signal(SIGPIPE, my_function);

但它会停止。

一些代码:

int main(int argc, char *argv[])
{

while(1) {          

    if(reconnect){
        close(fd);
        fd = createSocket(argv[1]);
        reconnect=0;
    }

reconnect = connectionTest(fd);

}


int connectionTest(int *fd) {

  numbytes=send(fd, buf, 100,0);

  if ((numbytes = recv(fd, reply, 100, 0)) == -1) {
/* HERE IT STOPS */
    perror("recv");
    printf("\n error while test recv 1");

    reconnect = 1;

  }

    return reconnect;
}

int createSocket(char *server_addr){

 int sockfd;
 struct addrinfo hints, *servinfo, *p;
 int rv;
 char s[INET6_ADDRSTRLEN];
 int set = 1;

signal(SIGPIPE, SIG_IGN);

printf("connect to: %s", server_addr); 

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;

    if ((rv = getaddrinfo(server_addr, PORT, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return 1;
    }

    // loop through all the results and connect to the first we can
    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                p->ai_protocol)) == -1) {
            perror("client: socket");
            continue;
        }
        else printf("socketd created! \n");

    int set = 1;
setsockopt(sockfd, SOL_SOCKET, MSG_NOSIGNAL, (void *)&set, sizeof(int));

      if (setsockopt( sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&set, sizeof(int)) < 0 )
      perror("setsockopt failed \n");

struct timeval timeout;
  timeout.tv_sec = 4;
  timeout.tv_usec = 0;


      if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0 ) 
      perror("setsockopt failed \n");

      if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)) < 0 ) 
      perror("setsockopt failed \n");

      printf("Try to connect \n");
      if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
        close(sockfd);
        perror("client: connect");
      }
      else {
        printf("i have connection");
        break;
     }
   }

printf("next1");  

    if (p == NULL) {
        fprintf(stderr, "client: failed to connect\n");
        return 2;
    }

    inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
            s, sizeof s);
    printf("client: connecting to %s\n", s);
    freeaddrinfo(servinfo); // all done with this structure

return  sockfd;
}

2 个答案:

答案 0 :(得分:1)

read() 返回EPIPE。

如果针对另一方已write()甚至shutdown()的连接发出close(),则无论如何都会发出错误。

引发SIGPIPE,如果没有处理也没有被阻止,进程将终止。如果SIGPIPE被处理或阻止,write()将返回-1并将errno设置为EPIPE

答案 1 :(得分:0)

您的计划可能会停在recv,因为它会收到SIGPIPE信号。

如果您已尝试使用signal(SIGPIPE, SIG_IGN)忽略此信号,请注意您应该在启动任何线程之前执行此操作,否则可能会在忽略之前捕获信号。


另请注意,您可以使用setsockopt配置套接字,以便不生成SIGPIPE信号:

int optval = 1;
setsockopt(cs, SOL_SOCK, SO_NOSIGPIPE, (void *)&optval, sizeof(int))

您的系统可能无法使用此功能。


您的系统也可能允许您使用recv中的MSG_NOSIGNAL选项来避免SIGPIPE信号的升高:

recv(fd, odp, 100, MSG_NOSIGNAL ))

我认为它适用于Linux 2.2 +


正确忽略信号后,您的recv应该返回,您应该能够处理错误。

修改

此处您可能遇到XY问题,如果您想检测管道是否损坏,您实际上不必阅读或写入,您可以使用{{3} },另见:poll