简体   繁体   English

为什么select()返回1但recv()返回0?

[英]Why is select() returning 1 but recv() returning 0?

I can see clearly that recvbuf has all the data I was expecting yet select() keeps returning 1. 我可以清楚地看到recvbuf具有我期望的所有数据,而select()仍然返回1。

Right now it's stuck in the limbo of else if (iBuffer == 0) {} . 现在, else if (iBuffer == 0) {}它会陷入else if (iBuffer == 0) {}困境。

SOCKET m_ConnectSocket;
/* The socket setup is done elsewhere but just adding this for clarity
   This socket is responsible for sending from the client to the server
   and also receives anything the server sends back.

   This socket is doing the connect() & initial send()
*/

fd_set set;
struct timeval timeout;

// Set up the file descriptor set.
FD_ZERO(&set);
FD_SET(m_ConnectSocket, &set);

// Set up the struct timeval for the timeout.
timeout.tv_sec  = RECV_DELAY_SEC;
timeout.tv_usec = RECV_DELAY_USEC;

int iBuffer = 0;

do
{
    iResult = select(m_ConnectSocket, &set, NULL, NULL, &timeout);
    if (iResult > 0)
    {
        iBuffer = recv(m_ConnectSocket, recvbuf, DEFAULT_BUFLEN, 0);
        if (iBuffer > 0)
        {
            string sRecv(recvbuf);

            STrace = String::Format("Bytes Received: {0}", iBuffer);
            Trace(STrace, TRACE_INFO);

            STrace = String::Format("Data Received: [{0}]", gcnew String(sRecv.c_str()));
            Trace(STrace, TRACE_INFO);
        }
        else if (iBuffer == 0)
        {
            STrace = String::Format("iBuffer empty");
            Trace(STrace, TRACE_INFO);
        }
        else
        {
            STrace = String::Format("recv failed: {0}", WSAGetLastError());
            Trace(STrace, TRACE_ERROR);
        }
    }
    else if (iResult == 0)
    {
        STrace = String::Format("No data left in buffer");
        Trace(STrace, TRACE_INFO);

        pMessage->Data(recvbuf);
        if (iSentType != pMessage->Type())
        {
            STrace = String::Format("Message type mismatch: {0} | Expected: {1}", (int)pMessage->Type(), (int)iSentType);
            Trace(STrace, TRACE_WARNING);
        }
    }
    else if (iResult == -1)
    {
        STrace = String::Format("select() error");
        Trace(STrace, TRACE_ERROR);
    }
} while (iResult > 0);

All the answers so far are correct in what they say about resetting the FD sets, but none of them has actually identified the underlying problem. 到目前为止,他们所说的关于重置FD集的所有答案都是正确的,但是他们都没有真正确定潜在的问题。

If recv() returns zero it means the peer has disconnected, and you must close the socket. 如果recv()返回零,则表示对等方已断开连接,您必须关闭套接字。 If you don't, as you aren't, you will continue to select the socket as readable and continue to receive zero. 如果不这样做,您将继续选择套接字可读并继续接收零。

It does not mean 'buffer empty'. 并不意味着“缓冲空”。

As select has it parameters passed as pointer and those data structures get altered by select put 因为select将参数作为指针传递,并且这些数据结构会被select put改变

fd_set set;
struct timeval timeout;

// Set up the file descriptor set.
FD_ZERO(&set);
FD_SET(m_ConnectSocket, &set);

// Set up the struct timeval for the timeout.
timeout.tv_sec  = RECV_DELAY_SEC;
timeout.tv_usec = RECV_DELAY_USEC;

Just before the select statement ie within the loop. 就在select语句之前,即在循环内。

You are misusing select() . 你在滥用select() Please read the documentation : 请阅读文档

Parameters 参数

nfds [in] nfds [in]
Ignored . 被忽略了 The nfds parameter is included only for compatibility with Berkeley sockets. 仅包含nfds参数以与Berkeley套接字兼容。

... ...

Upon return, the structures are updated to reflect the subset of these sockets that meet the specified condition. 返回时,更新结构以反映满足指定条件的这些套接字的子集。

So you must reset the fd_set structure every time you call select() in your loop. 因此,每次在循环中调用select()必须重置fd_set结构。

Also, it looks like when select() times out, you are trying to parse whatever was received, but you are only parsing the last buffer that was returned by the last successful recv() , if any. 此外,看起来当select()超时时,您试图解析收到的任何内容,但您只解析上一次成功的recv()返回的最后一个缓冲区recv()如果有)。 In case recv() has to be called multiple times before the data times out, you need to collect each returned buffer and then parse them all together as a whole. 如果必须在数据超时之前多次调用recv() ,则需要收集每个返回的缓冲区,然后将它们作为一个整体解析。

Also, your error handling in general could use some improvement, too. 此外,您的错误处理通常也可以使用一些改进。

Try something more like this instead: 尝试更像这样的东西:

fd_set set;
struct timeval timeout;

string sBuffer;
int iBuffer;

do
{
    // Set up the file descriptor set.
    FD_ZERO(&set);
    FD_SET(m_ConnectSocket, &set);

    // Set up the struct timeval for the timeout.
    timeout.tv_sec  = RECV_DELAY_SEC;
    timeout.tv_usec = RECV_DELAY_USEC;

    iResult = select(0, &set, NULL, NULL, &timeout);
    if (iResult > 0)
    {
        iBuffer = recv(m_ConnectSocket, recvbuf, DEFAULT_BUFLEN, 0);
        if (iBuffer > 0)
        {
            string sRecv(recvbuf, iBuffer);

            STrace = String::Format("Bytes Received: {0}", iBuffer);
            Trace(STrace, TRACE_INFO);

            STrace = String::Format("Data Received: [{0}]", gcnew String(sRecv.c_str()));
            Trace(STrace, TRACE_INFO);

            sBuffer += sRecv;
        }
        else
        {
            if (iBuffer == 0)
            {
                STrace = String::Format("Connection closed");
                Trace(STrace, TRACE_INFO);
            }
            else
            {
                STrace = String::Format("recv failed: {0}", WSAGetLastError());
                Trace(STrace, TRACE_ERROR);
            }
            break;
        }
    }
    else if (iResult == 0)
    {
        STrace = String::Format("No data left in buffer");
        Trace(STrace, TRACE_INFO);

        pMessage->Data(sBuffer.c_str());
        if (iSentType != pMessage->Type())
        {
            STrace = String::Format("Message type mismatch: {0} | Expected: {1}", (int)pMessage->Type(), (int)iSentType);
            Trace(STrace, TRACE_WARNING);
        }
    }
    else
    {
        STrace = String::Format("select failed: {0}", WSAGetLastError());
        Trace(STrace, TRACE_ERROR);
    }
}
while (iResult > 0);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM