c++ - 如何使用 C/C++ 套接字从 HTTP 读取二进制文件
问题描述
我正在编写 Http-Client,它在某个文件上获取 URL,下载它并将其保存在磁盘上。就像 curl 一样。我只能将 C/C++ 与 std:: 和 libc 一起使用。我下载 XML、CSV 或 txt 等文本文件没有问题,因为它们按应有的方式保存,如果在编辑器中打开它们 - 没关系,有预期的文本。但是当我下载 tar 或 pdf 并尝试打开它们时,它会告诉我文件已损坏。
这是我的类 HttpClient 的 2 个主要方法。HttpClient::get - 向主机发送 Http-request,在 URL 中提到,并调用第二个主要方法 - HttpClient::receive,它定义了什么样的数据 - 二进制或文本,并写入整个 Http-request 正文在使用二进制或文本模式的文件中。我决定不展示所有其他方法,但如果有人需要,我可以。
HttpClient::get:
bool HttpClient::get() {
std::string protocol = getProtocol();
if (protocol != "http://") {
std::cerr << "Don't support no HTTP protocol" << std::endl;
return false;
}
std::string host_name = getHost();
std::string request = "GET ";
request += url + " HTTP/" + HTTP_VERSION + "\r\n";
request += "Host: " + host_name + "\r\n";
request += "Accept-Encoding: gzip\r\n";
request += "Connection: close\r\n";
request += "\r\n";
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
std::cerr << "Can't create socket" << std::endl;
return false;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(HTTP_PORT);
raw_host = gethostbyname(host_name.c_str());
if (raw_host == NULL) {
std::cerr << "No such host: " << host_name << std::endl;
return false;
}
if (!this->connect()) {
std::cerr << "Can't connect" << std::endl;
return false;
} else {
std::cout << "Connection established" << std::endl;
}
if (!sendAll(request)) {
std::cerr << "Error while sending HTTP request" << std::endl;
return false;
}
if (!receive()) {
std::cerr << "Error while receiving HTTP response" << std::endl;
return false;
}
close(sock);
return true;
}
HttpClient::接收:
bool HttpClient::receive() {
char buf[BUF_SIZE];
std::string response = "";
std::ofstream file;
FILE *fd = NULL;
while (1) {
size_t bytes_read = recv(sock, buf, BUF_SIZE - 1, 0);
if (bytes_read < 0)
return false;
buf[bytes_read] = '\0';
if (!file.is_open())
std::cout << buf;
if (!file.is_open()) {
response += buf;
std::string content = getHeader(response, "Content-Type");
if (!content.empty()) {
std::cout << "Content-Type: " << content << std::endl;
if (content.find("text/") == std::string::npos) {
std::cout << "Binary mode" << std::endl;
file.open(filename, std::ios::binary);
}
else {
std::cout << "Text mode" << std::endl;
file.open(filename);
}
std::string::size_type start_file = response.find("\r\n\r\n");
file << response.substr(start_file + 4);
}
}
else
file << buf;
if (bytes_read == 0) {
file.close();
break;
}
}
return true;
}
我找不到帮助,但我认为二进制数据是以某种方式编码的,但如何解码呢?
解决方案
感谢大家。我通过更改response += buf;
toresponse.append(buf, bytes_read);
和file << buf;
to解决了这个问题file.write(buf, bytes_read);
。编写像空终止字符串这样的二进制数据是愚蠢的。
推荐阅读
- php - 尝试通过替换 2 个占位符 php 来包含电子邮件模板
- amp-html - AMP 的可滚动水平标签
- javascript - JavaScript 没有“取消点击”按钮及其影响 Flask
- c++ - 如果我在 func testcase() 代码中声明 q[30005] 似乎不起作用,但如果我在全局范围内声明它或像 2000 那样采用更小的尺寸,代码运行良好
- python - 我应该如何在 django 中安排我的视图模板?
- c# - FormClosed 事件是否可以多次触发
- c++ - 错误:没有匹配函数调用 'sf::RenderWindow::draw(
)'| C++ 中的 SFML - javascript - Cloudflare Workers Buffer.from()
- apache-kafka - 如何过滤Kafka中的数据?
- php - 在 WooCommerce“我的帐户”仪表板上显示最新订单