设置connect()函数的超时时间c中的tcp套接字编程中断recv()

时间:2013-01-10 08:59:36

标签: c tcp

在我的程序中如果服务器无法访问,则connect函数会占用太多时间。所以我尝试使用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;
}

4 个答案:

答案 0 :(得分:6)

  

设置connect()函数的超时时间C中的tcp套接字编程无法正常工作

校正。设置连接超时 正常工作。什么“不起作用”是后续的recvfrom(),那是因为你以非阻塞模式离开套接字而你不知道如何处理结果EAGAIN.所以要么处理,通过使用select()告诉您套接字何时可以读取,或者在完成连接后将套接字重新置于阻塞模式。

答案 1 :(得分:5)

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

man recvfrom

看一下
  

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

另一个案例可能如下:

  • 您的套接字可能已连接,但您检查是否收到了某些内容的速度太快。为了避免这种情况,请在recvfrom之前添加另一个select,以便从套接字缓冲区中提取数据包(调用{{只有在您确定收到某些内容时才会发出1}}或readfrom}。

答案 2 :(得分:5)

第一次成功选择意味着连接操作已完成但并不一定意味着它成功,从connect手册页,您应该检查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。

答案 3 :(得分:5)

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

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