Winsock recv() 不阻塞

Posted

技术标签:

【中文标题】Winsock recv() 不阻塞【英文标题】:Winsock recv() does not block 【发布时间】:2010-11-11 20:51:04 【问题描述】:

我刚刚编译了这段代码: http://www.win32developer.com/tutorial/winsock/winsock_tutorial_2.shtm

我添加了一些代码,因此它会在无限循环中执行 recv()。我的问题,如果没有数据可以读取,它仍然不会阻塞。

如果我认为 recv 应该阻止我的情况,我完全错了吗?

我添加的代码是:

for(;;)

  char buffer[1000];
  memset(buffer,0,999);
  int inDataLength = recv(Socket,buffer,1000,0);

  int nError=WSAGetLastError();
  if(nError!=WSAEWOULDBLOCK&&nError!=0)
  
    std::cout<<"Winsock error code: "<<nError<<"\r\n";
    std::cout<<"Client disconnected!\r\n";

    // Shutdown our socket
    shutdown(Socket,SD_SEND);

    // Close our socket entirely
    closesocket(Socket);

    break;
  

它位于末尾,在std::cout&lt;&lt;"Client connected!\r\n\r\n"; 行之后。 我知道我从一个“非阻塞”示例中复制了这个,但我认为这段代码不应该做任何非阻塞的事情,但我的 for 循环正在疯狂地运行!

【问题讨论】:

你能粘贴你写的附加代码吗? 您是否在使用任何 WSAsync... 调用? 你有什么样的客户端连接到你的服务器? @chrisaycock:我通过 php 连接到它。 【参考方案1】:

recv 默认情况下应该阻塞,除非有套接字错误或者你明确地将套接字设置为非阻塞。请务必检查返回值是否有错误。有关详细信息,请参阅recv 上的 Microsoft MSDN 文章。

【讨论】:

【参考方案2】:

循环没有正确检查错误。它需要更像这样:

char buffer[1000]; 
int inDataLength;

do 
    
    inDataLength = recv(Socket, buffer, sizeof(buffer), 0); 
    if (inDataLength > 0)
        
        // inDataLength number of bytes were received, use buffer as needed...
        continue;
        

    if (inDataLength == 0)
        
        std::cout << "Client disconnected!" << std::endl; 
        break;
        

    int nError = WSAGetLastError(); 
    if (nError != WSAEWOULDBLOCK)
        
        std::cout << "Winsock error code: " << nError << std::endl; 
        break;
        

    // optionally call select() here to wait for the socket
    // to receive data before calling recv() again...
    /*
    fd_set fd;
    FD_ZERO(&fd);
    FD_SET(Socket, &fd);

    timeval tv;
    tv.tv_sec = ...;
    tv.tv_usec = ...;

    nError = select(Socket+1, &fd, NULL, NULL, &tv);
    if (nError == 0)
        
        std::cout << "Timeout waiting for data" << std::endl; 
        break;
        

    if (nError == SOCKET_ERROR)
        
        nError = WSAGetLastError();
        std::cout << "Winsock error code: " << nError << std::endl; 
        break;
        
    */
     
while (true);

// Shutdown our socket 
shutdown(Socket, SD_SEND); 

// Close our socket entirely 
closesocket(Socket); 

【讨论】:

【参考方案3】:
if((nError == SOCKET_ERROR) || (nError == 0))
    WSAGetLastError();
else
    ; // handle success

这就是它应该看起来的样子,而不是你做的样子。

【讨论】:

澄清一下:'WSAEWOULDBLOCK' 适用于 非阻塞 套接字。并且,仅当返回代码为“SOCKET_ERROR”(-1) 时才应检查 WSAGetLastError()。 @Rob:如果我不使用 WSAGetLastError(),nError 如何获得它的价值? @Poni:对不起,我指的是波尼,不是罗布。 Easy Mike,在第一次使用 nError 时(在调用 recv() 之后)查看指示符 - “是否发生了错误?如果是,我应该看看它是什么”。因此,如果 nError 一开始会指示某些内容已写入,那么您只需使用 WSAGetLastError() 将提供扩展信息,并且 nError 可以获取其值,使其进入第二阶段。如果不对 WSAGetLastError() 返回的值使用 nError 则没有问题,那么 nError 只是一个指标。在一分钟内看到下一条评论,我会送你到正确的页面。 这里,检查“返回值”子句:msdn.microsoft.com/en-us/library/ms740121%28VS.85%29.aspx

以上是关于Winsock recv() 不阻塞的主要内容,如果未能解决你的问题,请参考以下文章

如何中止winsock阻塞调用?

面临 recv() 和 send() winsock api 的问题。 Recv() 在接收最后一个数据包时挂起

Select模型

同时执行 recv() 和 send() winsock

Winsock recv() 返回不正确的数据

winsock 服务器同时发送和接收