c++ - C++ HTTP客户端recv()和写入文件问题

标签 c++ http websocket httprequest

我用c++编写了HTTP客户端,以便在后台下载文件,并且它能勤奋地工作,但是当我下载通常不会损坏的pdf时,它会损坏。

有一些类似libcurl poco的库,但是由于我想了解基础知识,所以我写了纯套接字代码。我看了库的源代码(例如curl),但是我对它们一无所知。

file.pdf地址:https://www.axmag.com/download/pdfurl-guide.pdf

这是我的代码:

#include <iostream>
#include <stdio.h>
#include <WS2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
void main()
{
setlocale(LC_ALL,
    "Turkish");




WSADATA wsdata;
WORD ver = MAKEWORD(2, 2);


int ws0k = WSAStartup(ver, &wsdata);

if (ws0k != 0) {
    return;
}// classic startup operations


SOCKET client = socket(AF_INET, SOCK_STREAM, 0);

if (client == INVALID_SOCKET) {
    return;
}
else {
    cout << "Soket oluşturuldu." << endl; // successfully created socket
}



struct hostent* host;
host = gethostbyname("www.axmag.com");


sockaddr_in target;
target.sin_addr.S_un.S_addr = *((unsigned long*)host->h_addr); //WEBSITE ADDRESS
target.sin_port = htons(80); // HTTP PORT : 80
target.sin_family = AF_INET; // I don't know the address family of http.

int conn = connect(client, (sockaddr*)&target, sizeof(target));

if (conn < 0) {
    return;
}
else {
    cout << "Bağlantı isteği başarılı." << endl; // successfully connected.
}


char HTTP_MESSAGE[] = "GET /download/pdfurl-guide.pdf HTTP/1.0\r\nHost: www.axmag.com\r\nConnection: close\r\n\r\n";


if (send(client, HTTP_MESSAGE, sizeof(HTTP_MESSAGE), 0) < 0) { // send http request.
    return;
}
else {
    cout << "Komut başarıyla gönderildi." << endl; // Successfully send http request.
}


FILE* file = NULL; // file

file = fopen("C:\\Users\\user\\Desktop\\test.pdf", "wb"); //Create file

if (file == NULL) {
    return;
}
else {
    cout << "Dosya oluşturuldu." << endl; //Successfully created file.
}

char recvbuf[1024];


int received;
while (received = recv(client, recvbuf, sizeof(recvbuf), 0) > 0) { // RECV
    cout << recvbuf << endl;
    fwrite(recvbuf, 1, received, file); // write data to file

}



fclose(file);
closesocket(client);
WSACleanup();

system("pause");
}   

我下载成功了。问题出在fwrite函数上。
我将ElementSize参数更改为缓冲区的值,并且它发生了。

解决方案代码:
char recvbuf[64];

int received;

while (received = recv(client, recvbuf, sizeof(recvbuf), 0) > 0) { // RECV
    cout << recvbuf << endl;
    fwrite(recvbuf, 64, received, file); // write data to file
}

最佳答案

一旦出现问题,那就是>的运算符优先级高于=的运算符优先级,因此您的received变量将获得01。您可以使用一组额外的括号来解决此问题:

while ((received = recv(client, recvbuf, sizeof(recvbuf), 0)) > 0) {
...

当Web服务器发回其响应时,响应将包括HTTP响应 header 。您需要读取此响应头并将其保留在文件之外。

简单地说,
// Skip the HTTP header
std::string http_resp;
auto eoh = std::string::npos;
while ((received = recv(client, recvbuf, sizeof(recvbuf), 0)) > 0) {
    http_resp.append(recvbuf, received);
    auto eoh = http_resp.find("\r\n\r\n");
    if (eoh != std::string::npos) {
        if ((eoh + 4) < http_resp.size()) {
            auto rest = http_resp.substr(eoh + 4);
            fwrite(rest.c_str(), 1, rest.size(), file);
        }
        break;
    }
}

// Get the rest of the file
if (received > 0) {
    while ((received = recv(client, recvbuf, sizeof(recvbuf), 0)) > 0) {
        fwrite(recvbuf, 1 ,received, file);
    }
}

关于c++ - C++ HTTP客户端recv()和写入文件问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59686010/

相关文章:

c++ - 获取当前图像基地址

http - 如何使用 httptest 在 Go 中测试 http 调用

go - JSON-RPC方式获取websocket连接信息

javascript - 从 websocket 获取过去的消息

c++ - dsym 文件 UUID 与 xx 中的不匹配,Eclipse CDT 中未加载符号表

C++ 重载运算符、常量参数还是按值传递?

java - python cgi http响应向内容添加额外的字节

php - Symfony 2 网络套接字

c++ - 建立一个形状类三角形

javascript - XMLHttpRequest 读取外部文件