0

我正在写一个聊天程序,我的接收函数有时根本不等待。这是接收代码:重要部分基本上是前半部分,但我已经添加了整个函数以防万一。(编辑:评论是给我自己的,不是给你们阅读的笔记!对不起!)

ReceiveStatus Server::Receive(PacketInternal*& packetInternalOut)
{
    fd_set fds ;
    int n ;
    struct timeval tv ;

    // Set up the file descriptor set.
    FD_ZERO(&fds) ;
    FD_SET(*p_socket, &fds) ;

    // Set up the struct timeval for the timeout.
    tv.tv_sec = NETWORKTIMEOUTSEC ;
    tv.tv_usec = NETWORKTIMEOUTUSEC ;

    // Wait until timeout or data received.
    n = select ( *p_socket, &fds, NULL, NULL, &tv ) ;
    if ( n == 0)
    { 
        return ReceiveStatus::ReceiveTimeout;
    }
    else if( n == -1 )
    {
        return ReceiveStatus::ReceiveSocketError;   
    }

    //need to make this more flexible so it can support others
    sockaddr_in fromAddr;
    int flags = 0;
    int fromLength = sizeof(fromAddr);

    char dataIn[TOTALPACKETSIZE];
    int bytesIn = recvfrom(*p_socket, dataIn, TOTALPACKETSIZE, flags, (SOCKADDR*)&fromAddr, &fromLength);
    // Convert fromAddr into ip, port
    if(bytesIn == SOCKET_ERROR)
    {
        return ReceiveStatus::ReceiveSocketError;
    }
    if(bytesIn > 0)
    {
        memcpy(packetInternalOut,dataIn,bytesIn);
        return ReceiveStatus::ReceiveSuccessful;
    }
    else
    {
        return ReceiveStatus::ReceiveEmpty;
    }

}

有什么可以影响这是否有效吗?我的聊天程序可以是服务器或客户端。他们都使用相同的代码。服务器在等待连接时,在 Select() 上停留 100 秒,因为 NETWORKTIMEOUTSEC = 100。但是在 char 程序中,每当我想发送消息时,我首先发送一个传输请求,然后我等待一个确认(对于确认包,我需要再次调用接收)。现在这是不等待的步骤. 我的 ReceiveAck 函数调用 Receive(),并且接收直接在整个代码上运行。我可以通过创建客户端而不是服务器来测试这一点。如果我在没有服务器的情况下发送消息,它应该等待 100 秒以获得确认,然后超时。但是相反,只要我按 Enter 键,它就会说超时。

我不知道是什么让它跳过这一步。我已经在服务器和客户端状态下调试了我的聊天程序。tv 和 fds 的值在两者中是相同的,但是服务器会等待而客户端不会......

4

3 回答 3

4

第一个参数 toselect()比最后一个套接字大一个。所以你需要:

n = select ( *p_socket + 1, &fds, NULL, NULL, &tv ) ;
于 2012-03-07T04:54:39.277 回答
0

select()应始终在循环中使用。您必须在三个条件下检查它的回报:

  • -1(错误),您必须对其进行评估以确定它是否是致命的。 EINTR是一个非致命错误的例子。
  • 一个零,在这种情况下,已经过去了一些不确定的时间,如果你关心它有多长时间,你需要单独检查时间。
  • 一个正值,在这种情况下,您应该检查所有标记的描述符并对其进行操作。

在所有情况下,您都应该检查是否存在任何其他可能使您想要退出循环的条件,例如实际经过了多长时间。

请注意,第一个参数select()通常应该是常量FD_SETSIZE。将其设置为其他任何东西都没有什么好处。

另请注意,仅仅因为您收到了数据报并不意味着您收到了您想要的数据报。你需要一种方法来检查你没有得到一些碰巧在网络上浮动的随机数据报(它发生了)。沿着这些思路,确保TOTALPACKETSIZE是 65536,因为理论上(大约)这是随机数据包的大小。

于 2012-03-07T22:38:31.247 回答
0

当您的应用程序被信号击中时,Select 也会提前返回(即,没有任何套接字存在数据)。因此,如果您的应用程序在不同的线程中使用了很多 usleep() 和朋友,您可能会感到惊讶。

于 2012-03-07T13:09:54.060 回答