【问题标题】:WinSock Chunked Data EncodingWinSock 分块数据编码
【发布时间】:2013-01-01 18:54:47
【问题描述】:

当我连接到某些网站时,它给了我:

Content-Type: text/html; charset=ISO-8859-1

Connection: close

Transfer-Encoding: chunked

Date: Tue, 01 Jan 2013 18:49:53 GMT   


fff8

在文件的末尾,它看起来像:

</script><!-- vBadvanced 1-3-9-4-8-0 -->

</body>
</html

1

>

0

但是当我使用 stackoverflow.com 时,它的打印结果非常好。它可能在源代码中有额外的空白行,但这很好。为什么其他站点添加数字?

我该如何解决?另外,如何将该标头与 html 本身分开?

我的代码如下:

#define _WIN32_WINNT 0x501

#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <fstream>
#include <vector>

using namespace std;

void Get(string WebPage)
{
    WSADATA wsaData;
    string Address;
    struct addrinfo *result;
    struct sockaddr_in  *sockaddr_ipv4;

    char Buffer[99000];

    string Header = "GET / HTTP/1.1\r\n";
    Header += "Host: " + WebPage + "\r\n";
    Header += "Connection: close\r\n";
    Header += "\r\n";

    if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) return;

    SOCKET Socket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

    getaddrinfo(WebPage.c_str(), NULL, NULL, &result);
    if (result->ai_family == AF_INET)
    {
        sockaddr_ipv4 = (struct sockaddr_in *) result->ai_addr;
        Address = inet_ntoa(sockaddr_ipv4->sin_addr);
    }
    freeaddrinfo(result);


    SOCKADDR_IN SockAddr;
    memset(&SockAddr, 0, sizeof(SockAddr));
    SockAddr.sin_port = htons(80);
    SockAddr.sin_family = AF_INET;
    SockAddr.sin_addr.s_addr = inet_addr(Address.c_str());

    if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr)) == SOCKET_ERROR) return;

    if (send(Socket, Header.c_str(), Header.size(), 0) == SOCKET_ERROR) return;
    shutdown(Socket, SD_SEND);

    std::string Response;

    int bytes = 1;
    while (bytes > 0)
    {
        bytes = recv(Socket, Buffer, sizeof(Buffer), 0);
        Buffer[bytes] = '\0';
        Response.append(Buffer, bytes);
    };

    closesocket(Socket);
    WSACleanup();
}

int main()
{
    Get("google.com");
}

【问题讨论】:

标签: c++ sockets winsock2 http-chunked


【解决方案1】:

查看此 wiki 页面:http://en.wikipedia.org/wiki/Chunked_transfer_encoding

这些十六进制数字(块长度)中的每一个后面都是指定大小的实际块数据(有效负载),紧接着是另一个块长度。如果块长度为零,则后面不再有数据字节 (eof)。这些元素由换行符分隔。 我不确定您发布的内容是否可以正确连接,您似乎需要处理多个连续的换行符。只需在浏览器中查看页面及其来源即可。

编辑:

刚刚找到了这个嗅探工具,它显示了我想知道的所有细节:

http://web-sniffer.net/

【讨论】:

  • 我尝试通过 CRLF 拆分响应字符串,仍然无法弄清楚如何找到哪个块是哪个块或如何从文件顶部删除标题数据.. 不过没关系。我会继续努力的。
  • 每个header属性都以CRLF结尾,header本身又以一个额外的CRLF结尾(可视为空header属性)。之后,您应该处于第一个块长度(fff8)的位置。看来,您在复制数据时多了一个换行符(可能是转换问题,CR 和 LF 有单独的换行符)。
  • 注意,分块编码允许服务器省略'Content-Length'属性。您应该检查最后的零块长度或标题中为另一个传输编码指定的大小。
  • @Sam: RFC 2616 Section 3.6.1 定义了块的格式。每个块中都有两个 CRLF - 一个在块大小之后,一个在块数据之后。当Transfer-Encoding 存在时,Content-Length 不应该存在,如果存在则必须忽略它。这在RFC 2616 Section 4.4 中有明确说明。
  • 对于这两个CRLF,我的意思是问题内容中的连续的,(或者我只是没有得到,你的意思是什么?)。如您所述,删除Content-Length 的能力(或更准确地说是要求)构成了分块模式的优势。恕我直言,这些网络“标准”就像丛林。在没有终止规则的传输编码的情况下,假设在高级 MIME 容器中使用类似于引用的可打印编码之类的东西时,将再次需要长度,这反过来又需要一个唯一的分隔符。
【解决方案2】:

此功能将“解块”您的 HTTP 数据 - 在 VB6 中,但您会明白的(真的是旧代码)

Private Function UnChunk(Indata As String) As String
  If InStr(LCase(Indata), "transfer-encoding:") = 0 And InStr(LCase(Indata), "chunked") = 0 Then
    'not chunked, so return the input
    UnChunk = Indata
    Exit Function
  End If
  'can't let this crash
  On Error GoTo returnInData

  Dim crlfstart As Long
  Dim crlfend As Long
  Dim chunksize As Long

  'first, get header, which ends with 2 line feeds
  crlfstart = InStr(Indata, vbCrLf & vbCrLf)
  If crlfstart = 0 Then
    'invalid http
    UnChunk = Indata
    Exit Function
  End If
  UnChunk = Left(Indata, crlfstart + 2)

  'start looking for vbCrLf
  crlfstart = InStr(crlfstart + 2, Indata, vbCrLf)
  Do While crlfstart > 0
    'find the next vbCrLf
    crlfend = InStr(crlfstart + 1, Indata, vbCrLf)

    If crlfend > crlfstart And crlfend - crlfstart < 10 Then
      'convert the HEX string to the chunksize
      chunksize = Val("&h" & Mid(Indata, crlfstart + 2, crlfend - (crlfstart + 2)))
      'by spec, if 0 then no more data
      If chunksize > 0 Then
        'there's more data
        'this should be unnecessary, but one more test
        If Mid(Indata, crlfend + 2 + chunksize, 2) = vbCrLf Then
          UnChunk = UnChunk & Mid(Indata, crlfend + 2, chunksize)
        Else
          'oops, failed
          Exit Do
        End If
      Else
        'there's no more data so return what we have
        Exit Function
      End If
    End If
    'look again
    crlfstart = InStr(crlfstart + 1, Indata, vbCrLf)
  Loop
  'just in case this fails, return the input data
returnInData:
  UnChunk = Indata
End Function

【讨论】:

    猜你喜欢
    • 2011-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-13
    • 2014-01-07
    • 1970-01-01
    • 1970-01-01
    • 2011-12-06
    相关资源
    最近更新 更多