1

当断开连接发生时,我试图“抓住”。但我实际上不明白出了什么问题。recv() 返回 0,errno 设置为 0,ioctl 返回 0。我在网上搜索了 6 个小时,但没有成功。谁能告诉我怎么了?

问候。

bool Network::setBlocking(bool blocking)
{
    // sets blocking or non-blocking mode.

    int flags = blocking ? 1 : 0; 
    return ioctl(this->sockfd, FIONBIO, &flags) ? false : true;
}

NetworkStatus Network::status()
{
    // returns socket status.

    struct timeval tv;
    fd_set  fd;
    int result = 0;

    tv.tv_sec  = 3;
    tv.tv_usec = 0;

    FD_ZERO(&fd);
    FD_SET(this->sockfd, &fd);

    result = select(this->sockfd + 1, &fd, 0, 0, &tv);

    if(result == -1)
    {
        return NETWORK_ERROR;
    }
    else if(result)
    {
        return NETWORK_READYREAD;
    }
    else
    {
        return NETWORK_TIMEOUT;
    }
}

int Network::bytesAvailable()
{
    // returns number of bytes available.

    int bytes = 0;

    if(ioctl(this->sockfd, FIONREAD, &bytes) < 0 || errno)
    {
        return -1;
    }

    return bytes;
}

int Network::read(char *buffer, int size)
{
    // reads data from socket.

    return recv(this->sockfd, buffer, size, 0);
}
...
int main(int argc, char* argv[])
{
    Network net;
    ...
    while(true)
    {
        switch(net.status())
        {
            ...
            case NETWORK_READYREAD:
            {
                int bytesAvailable = net.bytesAvailable();
                char temp[bytesAvailable];
                int len = net.read(temp, bytesAvailable);
                printf("len: %d\nerrno: %d\nbytesAvailable: %d\n", len, errno, bytesAvailable); // len: 0, errno: 0, bytesAvailable: 0
                break;
            }
        }
    } // status
    return 0;
}
4

2 回答 2

7

recv()对等方断开连接时返回零。你没有问题。这是预期的,正确的行为。

于 2013-07-24T04:24:53.317 回答
5

当对方关闭socket或者shutdown(Send)时,在你这边select会返回socket可读,所以select命令会返回1有数据要读取(其实没有数据,就是只是一个指示套接字已关闭的信号),但是作为可用字节ioctl返回并且也返回,这正是 TCP 的工作方式。因此,在您的程序中,您应该注意退货和/或退货。在这些情况下,套接字已关闭,您也应该关闭您的一侧并等待(接受)或建立(连接)新连接。0recv()0bytesAvaliable0read()0

编辑:添加评论:

嗯,不完全是。当recv() = 0,套接字关闭或关闭发送,当= -1套接字中有错误时。如果套接字是非阻塞的(已O_NONBLOCK设置),您应该检查错误(errno在 unix 上,WSAGetLastError()在 Windows 上)并且EWOULDBLOCKEAGAIN表明没有可用的数据并且套接字仍然有效。此外,在一些非常罕见的情况下,recv()可能会返回-1并且错误EINTR,这意味着在recv()操作期间已收到中断(信号),在这种情况下,您应该忽略错误(除非您正在等待此类信号)并重新发出recv().

ret=recv(socket, buff, length, 0);
if (ret > 0) 
{
    // data has been received
}
else if (ret == 0) 
{
    // socket has been closed or shutdown for send
}
else {
   // there is an error, let's see what it is
   int error = errno; // or WSAGetLastError()
   switch (error)
   {
         case EAGAIN:
         case EWOULDBLOCK: 
              // Socket is O_NONBLOCK and there is no data available
              break;
         case EINTR: 
              // an interrupt (signal) has been catched
              // should be ingore in most cases
              break;
         default:
              // socket has an error, no valid anymore
              return;
   }
}

话虽如此,您必须清楚的一件事是,如果recv()返回 0-1套接字不再有效并且应该关闭,但同样取决于许多因素,您用来保持套接字之间对话的协议,如果它不是-blocking 等。例如,对方可以发出shutdown(); 在这种情况下,您recv()将返回0,但您仍然可以send()通过该套接字进行操作而不会出错。

于 2013-07-24T10:25:30.333 回答