0

我对套接字中的 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;
}
4

2 回答 2

1

read()不得退回 EPIPE

如果 a是针对已经由另一方甚至是dwrite()的连接发出的,那么在任何情况下,发出过程都会出错。shutdown()close()

ASIGPIPE被提出,如果没有处理也没有被阻止,该过程将终止。如果SIGPIPE被处理或阻塞write()应返回-1并设置errnoEPIPE

于 2013-04-16T14:21:36.617 回答
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 问题,如果您想检测管道是否损坏,您实际上不必读取或写入它,您可以使用poll,另请参阅:Linux:检查套接字/管道是否不做 read()/write() 就坏了

于 2013-04-16T14:10:37.273 回答