【问题标题】:Setting time out for connect() function tcp socket programming in C breaks recv()在 C 中为 connect() 函数 tcp 套接字编程设置超时会中断 recv()
【发布时间】:2013-01-10 08:59:35
【问题描述】:

在我的程序中,如果无法访问服务器,则连接功能会花费太多时间。所以我尝试使用 select() 给时间连接。现在的问题是,当我尝试使用 recvfrom() 从服务器接收数据时,出现错误“EAGAIN”。这是用于连接和接收来自服务器的数据的代码。

int sock;
struct sockaddr_in addr;
int connectWithServer
{

    int status;

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

    addr.sin_port = htons(port);
    sock = socket (AF_INET,SOCK_STREAM,0);
    inet_pton(AF_INET,serverIP,&addr.sin_addr);

    fd_set set;
    FD_ZERO(&set);
    FD_SET(sock, &set);

    fcntl(sock, F_SETFL, O_NONBLOCK);

    if ( (status = connect(sock, (struct sockaddr*)&addr, sizeof(addr))) == -1)
    {
        if ( errno != EINPROGRESS )
            return status;

    }
    status = select(sock+1, NULL, &set, NULL, &timeout);

    return status;
}


long int receiveResponse (void *response , unsigned int length)
{
    socklen_t sockLen = sizeof(struct sockaddr);
    long int received = recvfrom(sock, response, length, 0,(struct sockaddr *)&addr,  &sockLen);
    printf("Received %ld bytes...  err %d\n",received, errno);

    return received;
}

【问题讨论】:

  • recvfromconnect 不匹配。第一个用于UDP套接字,后者与TCP相关
  • 但如果没有超时,它工作正常
  • 是的,它可以工作,但from 参数没用,因为你知道谁是对等方。无论如何,这只是一个建议

标签: c tcp


【解决方案1】:

在 C 中为 connect() 函数 tcp 套接字编程设置超时不起作用

更正。设置连接超时正在工作。 '不起作用'的是随后的recvfrom(),那是因为您将套接字置于非阻塞模式并且您不知道如何处理生成的EAGAIN. 所以,要么使用@ 来处理它987654323@ 告诉您套接字何时准备好读取,否则在完成连接后将套接字重新进入阻塞模式。

【讨论】:

    【解决方案2】:

    第一次成功选择表示连接操作完成,但不一定表示成功,从connect man page,你应该检查SO_ERROR以确保它成功完成

    可以通过选择 (2) 或轮询 (2) 来完成 用于写入的套接字。 select(2)表示可写后,使用 getsockopt(2) 在 SOL_SOCKET 级别读取 SO_ERROR 选项以 判断 connect() 是否成功完成(SO_ERROR 为零) 或不成功(SO_ERROR 是列出的常见错误代码之一 在这里,解释失败的原因)。

    所以在你的代码中你应该这样做:

    int ret;
    ret=select(sockfd+1, NULL, &wfds, NULL, NULL); //should use timeout
    if(ret==1 && getSocketOpt(sockfd, SO_ERROR) ==0) {
        return 0; //successfully connected
    }
    

    然后,如另一个答案中所述,您应该在从套接字写入或读取之前再次调用 select。

    【讨论】:

    • 感谢您的信息...有没有其他设置超时的方法
    • @RAJESH 是的,我认为可以使用信号,但我相信选择是惯用的方式,只需确保在选择连接后检查SO_ERROR
    • 很好的答案!我可以知道这里超时的推荐值是多少,即连接超时?
    • 如果 select() 返回 0 则表示套接字超时。如果返回 -1 则为错误。对于 >0,套接字上发生了一些有趣的事情。不值得根据这个来决定吗?为什么我们需要检查 SO_ERROR (我们是否在检查套接字仅在超时时连接的极端情况)?
    【解决方案3】:

    您收到EAGAIN,因为没有数据可从套接字缓冲区读取,并且您的套接字设置为nonblocking。由于您没有与同伴建立联系,我对此并不感到惊讶。

    man recvfrom看这个:

    如果套接字上没有可用的消息,则接收调用等待消息到达,除非套接字是非阻塞的(参见 fcntl(2)),在这种情况下返回值 -1 并设置外部变量 errno到 EAGAIN。接收调用通常会返回任何可用的数据,直到请求的数量,而不是等待收到请求的全部数量。

    另一种情况可能如下:

    • 您的套接字可能已连接,但您检查是否收到东西的速度太快。为避免这种情况,请在 recvfrom 之前放置另一个 select 以便从套接字缓冲区中提取数据包(调用 readfrom 或只是read) 仅在您确定收到某些东西时。

    【讨论】:

    • 选择的返回值表示它已连接
    • 你确定吗?在您的描述中,您告诉对等方无法访问。无论如何......选择的返回值是什么?您是否测试过您的套接字是由 FD_ISSET 触发的?
    • "1" 从 select() 中返回
    【解决方案4】:

    在调用 recv() 之前,应该再次将套接字设置为阻塞模式。

    fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) & ~O_NONBLOCK);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多