无法从 winsock 获取所有响应字节

Having trouble getting all bytes of response from winsock

我正在使用 winsocks 来执行我的 HTTP 请求。在我的服务器端,我 运行 PHP 获取文件内容的代码,base64 的内容,并打印它(回显)。在我的客户端 C++ 代码中,我执行了一个简单的 HTTP get 请求。我已经确认问题不在我的服务器端,而是在客户端。

客户端套接字代码:

locale local;
char buffer[1000000];
int i = 0;

string get_Website(string url, string path = "/", string useragent = "Mozilla") {
    string website_HTML;
    WSADATA wsaData;
    SOCKET Socket;
    SOCKADDR_IN SockAddr;
    int lineCount = 0;
    int rowCount = 0;
    struct hostent *host;
    string get_http;


    get_http = "GET " + path + " HTTP/1.0\r\nHost: " + url + "\r\nUser-Agent: " + useragent + "\r\nConnection: close\r\n\r\n";

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        cout << "WSAStartup failed.\n";
        system("pause");
        //return 1;-
    }

    Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    host = gethostbyname(url.c_str());

    SockAddr.sin_port = htons(44980);
    SockAddr.sin_family = AF_INET;
    SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);

    if (connect(Socket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr)) != 0) {
        cout << "Could not connect";
        system("pause");
        //return 1;
    }
    send(Socket, get_http.c_str(), strlen(get_http.c_str()), 0);

    int nDataLength;
    while ((nDataLength = recv(Socket, buffer, 1000000, 0)) > 0) {
        int i = 0;
        while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {

            website_HTML += buffer[i];
            i += 1;
        }
    }

    closesocket(Socket);
    WSACleanup();
    return website_HTML;
}

响应长度一直在变化,尽管我 return 每次服务器端的响应都是一样的。大缓冲区的原因是我认为这可能是问题所在,因为我正在检索整个文件 base64 编码形式。

本质上,问题是我没有收到 full/correct 响应。

 while ((nDataLength = recv(Socket, buffer, 1000000, 0)) > 0) {

这是从套接字中读取的。读取的字节数进入`nDataLength。紧接着:

    int i = 0;
    while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {

        website_HTML += buffer[i];
        i += 1;
    }

这个逻辑完全忽略了nDataLength中的字节数,只是盲目地读取缓冲区的内容,连续读取,直到第一个不是换行符或回车符的控制字符return。

除了对您的 HTTP 请求的响应肯定可以包含二进制字符这一事实之外,对您的 HTTP 请求的响应将以多个不同大小的数据包到达,这些数据包将一个接一个地写在彼此之上,连续地, buffer。分配的 buffer 似乎在静态存储中,因此它将被零初始化,并且单个数据包不太可能超过 999999 字节;所以循环不太可能 运行 离开缓冲区的末尾。它会在某个时候达到 [=15=]

但是,由于响应的数据包大小不一,较短的数据包将用其内容替换前一个数据包的初始较长内容;但是损坏的逻辑将无法检测到它,并且会吞掉新数据包,然后是前一个数据包的尾部。

有点乱。通过使用 nDataLength 来解决这个问题,将每个数据包的内容复制并附加到您的字符串中。