当前位置: 首页 > 知识库问答 >
问题:

recv()的Windows XP套接字错误

令狐灿
2023-03-14

有人知道这个问题吗?如何强制Windows XP也接收部分数据?

我将缓冲区大小(SO_RCVBUF)设置为1000字节。在Windows7上,这也反映到TCP窗口大小上--在XP上则不然。

这个问题的真正问题是,我不知道如何检查连接是否还活着。如何检查连接是否仍然有效?或者如何指定超时(从服务器接收的两个数据包之间的最大时间)?

共有1个答案

荣沈义
2023-03-14

默认情况下,套接字在阻塞模式下运行,因此您获得WSAEWOULDBLOCK错误的唯一方法是将套接字显式地置于非阻塞模式。这样,您就同意处理WSAEWOULDBLOCK(否则,不要使用非阻塞模式)。

wsaewouldblock并不是一个真正的错误,它只是表示您试图执行的操作在那一刻无法完成,因为它会阻塞调用线程。您需要检测到这个“错误”,然后在以后的时间,最好是检测到套接字状态改变之后,再次重试相同的操作。

对于recv()wsaewouldblock仅仅意味着此时套接字上没有可供读取的数据。在非阻塞模式下,应使用select()(或WSAEventSelect(),或WSAAsyncSelect(),或重叠I/O或I/O完成端口)检测入站数据,然后再读取入站数据。

也就是说,您正在实现一个HTTP客户端,因此您必须正确地遵循HTTP协议,而不管您使用的套接字I/O模式如何,也不管套接字缓冲区大小如何。对于另一个问题,您必须遵循我在此回答中概述的伪代码逻辑:

您必须遵循RFC2616中概述的规则。即:

>

  • 读取,直到遇到“\r\n\r\n”序列。现在不要再读取任何超过该值的字节。

    根据RFC 2616第4.4节中的规则分析接收到的报头。它们告诉您剩余响应数据的实际格式

    按照#2中发现的格式读取数据。

    如果响应使用HTTP 1.1,请检查接收的标头是否存在Connection:Close标头;如果响应使用HTTP 0.9或1.0,请检查是否缺少Connection:Keep-alive标头。如果检测到,请关闭套接字连接的端,因为服务器正在关闭其端。否则,保持连接打开并在后续请求中重用它(除非您已经使用了连接,在这种情况下请关闭它)。

    根据需要处理接收到的数据。

    简而言之,您需要做一些更像这样的事情来代替(伪代码):

    string headers[];
    byte data[];
    
    string statusLine = read a CRLF-delimited line;
    int statusCode = extract from status line;
    string responseVersion = extract from status line;
    
    do
    {
        string header = read a CRLF-delimited line;
        if (header == "") break;
        add header to headers list;
    }
    while (true);
    
    if ( !((statusCode in [1xx, 204, 304]) || (request was "HEAD")) )
    {
        if (headers["Transfer-Encoding"] ends with "chunked")
        {
            do
            {
                string chunk = read a CRLF delimited line;
                int chunkSize = extract from chunk line;
                if (chunkSize == 0) break;
    
                read exactly chunkSize number of bytes into data storage;
    
                read and discard until a CRLF has been read;
            }
            while (true);
    
            do
            {
                string header = read a CRLF-delimited line;
                if (header == "") break;
                add header to headers list;
            }
            while (true);
        }
        else if (headers["Content-Length"] is present)
        {
            read exactly Content-Length number of bytes into data storage;
        }
        else if (headers["Content-Type"] == "multipart/byteranges")
        {
            string boundary = extract from Content-Type header;
            read into data storage until terminating boundary has been read;
        }
        else
        {
            read bytes into data storage until disconnected;
        }
    }
    
    if (!disconnected)
    {
        if (responseVersion == "HTTP/1.1")
        {
            if (headers["Connection"] == "close")
                close connection;
        }
        else
        {
            if (headers["Connection"] != "keep-alive")
                close connection;
        }
    }
    
    check statusCode for errors;
    process data contents, per info in headers list;
    

    正如您所看到的,HTTP要求读取CRLF分隔的文本行或固定长度的原始字节。为此,您必须在循环中调用recv(),直到遇到终止CRLF或接收到预期的字节数为止。是使用在循环时忽略WSAEWOULDBLOCK错误的同步循环,还是使用由异步事件/回调驱动的状态机,这由您自己决定。这不会改变您必须如何处理HTTP协议。

    这适用于Windows的所有版本(甚至是使用BSD风格套接字API的所有平台)。您遇到的根本不是Windows bug。这是您在理解如何正确有效地使用套接字I/O时的一个潜在缺陷。

  •  类似资料:
    • 我在JMeter中运行了负载测试,得到了这个错误。非HTTP响应代码:javax.net.ssl。SSLException/非HTTP响应消息:java.net。SocketException:无法识别的Windows套接字错误:0:recv失败 为什么我得到这种错误??

    • 另外,除了调用recv函数后检查WSAGetLastError的值之外,是否还有其他方法可以使用TCP套接字库检测网络断开? 多谢!

    • 问题内容: 我有一个从服务器读取大文件并经常挂在特定计算机上的应用程序。它已经在RHEL5.2下成功运行了很长时间。我们最近已升级到RHEL6.1,现在可以正常挂起。 我创建了一个重现问题的测试应用。它可以挂在100中的98次。 我的测试中有一些注意事项: 如果“ localhost”映射到回送地址127.0.0.1,则该应用程序挂起对recv()的调用,并且永不返回。 如果“ localhost

    • 我正在编写一个简单的TCP客户端和服务器Perl脚本。到现在为止,我使用wireshark验证了三路TCP握手,并且建立了连接。但当我尝试发送或恢复数据时,什么也不会发生。 1)客户端和服务器之间的主要区别只是服务器增加了一个LISTEN参数,使它能够侦听传入的连接? 2)在recv和显示数据之间是否缺少任何步骤? 3)当程序第一次执行while循环时,难道不应该至少发送硬编码字符串“$respo

    • 问题内容: 我正在尝试做的事情: 我现在正在尝试构建一个测试应用程序,只需在Android手机(4.2.2)(作为客户端)上的应用程序与在PC上运行的Java应用程序(Windows8)(作为服务器)通过套接字连接。 我已经完成的工作: 我已经在PC上的Java中为客户端和服务器编写了程序,并对其进行了积极的测试(建立了Connection)。 网络: 我的手机和PC都连接到我家里的wifi。PC

    • 我试图使用任何NodeJS或NPM命令,但我总是得到以下错误: 套接字:(10106)无法加载或初始化请求的服务提供程序。 我正在运行Windows 10,我尝试再次重新安装nodejs,但仍然没有改变。