8

在我的程序中,如果无法访问服务器,则连接功能需要太多时间。所以我尝试使用 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

4 回答 4

6

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

更正。设置连接超时有效。'不工作'的是后续recvfrom(),那是因为你让套接字处于非阻塞模式并且你不知道如何处理结果EAGAIN.所以,要么处理它,通过使用select()告诉你套接字何时是准备好读取,否则在完成连接后将套接字恢复为阻塞模式。

于 2013-01-10T22:21:13.193 回答
5

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

fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) & ~O_NONBLOCK);
于 2013-08-19T05:45:45.513 回答
5

第一次成功选择表示连接操作完成,但不一定表示成功,从连接手册页,您应该检查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 。

于 2013-01-10T10:11:31.887 回答
5

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

看看这个man recvfrom

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

另一种情况可能如下:

  • 您的套接字可能已连接,但您检查是否收到东西太快了。为避免这种情况,请在 recvfrom 之前放置另一个选择,以便仅在您确定收到某些内容时从套接字缓冲区(调用readfrom或只是)中提取数据包。read
于 2013-01-10T09:18:08.800 回答