c++ - C原始套接字HTTP请求总是返回状态400
问题描述
我通常会写一堆 Typescript/Javascript 代码,我认为 HTTP 协议是理所当然的。我决定编写一个 C++ 程序,该程序可以使用套接字向给定 URL 发出 GET 请求,以了解有关 HTTP 工作原理的更多信息。我已经编写了我认为应该做的基本结构:
- 创建一个套接字
- 将套接字连接到主机
- 逐字节发送请求
- 逐字节接收响应
问题是请求总是返回状态码 400:
>>>> Request sent:
GET /links HTTP/1.1
>>>> Response received:
HTTP/1.1 400 Bad Request
Server: cloudflare
Date: Sun, 11 Oct 2020 05:57:11 GMT
Content-Type: text/html
Content-Length: 155
Connection: close
CF-RAY: -
<html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<hr><center>cloudflare</center>
</body>
</html>
这是我用来创建套接字并将其连接到主机的代码:
// ---- Create the socket
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) error("!!!! ERROR opening socket");
// ---- Look up (and parse) the server host, route
std::string host = parseHost(url);
std::string route = parseRoute(url);
struct hostent *server = gethostbyname(host.c_str()); // host.c_str())
if (server == NULL)
error("!!!! ERROR, no such host");
// ---- Fill in the server address structure
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT); // PORT
memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length);
// ---- Connect the socket to the given url's host
const int didConnect = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (didConnect < 0) error("!!!! ERROR connecting to host");
如果该逻辑看起来正确,那么这里是发送请求并接收响应的代码:
// ---- Send the GET request byte by byte
int bytes, sent, received;
char response[MAX_CONTENT_LENGTH];
int total = sizeof(response) - 1;
sent = 0;
std::string message = "GET " + route + "HTTP/1.1" + "\r\n\r\n";
do
{
bytes = write(sockfd, message.c_str() + sent, total - sent);
if (bytes < 0) error("!!!! ERROR writing message to socket");
if (bytes == 0) break;
sent += bytes;
} while (sent < total);
std::cout << ">>>> Request sent: \n" << message << std::endl;
// ---- Receive the response byte by byte
memset(response, 0, sizeof(response));
total = sizeof(response) - 1;
received = 0;
do {
bytes = read(sockfd, response + received, total - received);
if (bytes < 0)
error("!!!! ERROR reading response from socket");
if (bytes == 0)
break;
received += bytes;
} while (received < total);
if (received == total)
error("!!!! ERROR storing complete response from socket (not enough space allocated)");
- TLDR:我是否将正确的字符数组发送到服务器?截至目前,它具有以下格式:
"GET /route HTTP/1.1\r\n\r\n"
. 我是否忘记了任何让服务器知道它是 GET 请求的标头/其他信息?
解决方案
>>>> Request sent:
GET /links HTTP/1.1
这不是一个有效的 HTTP 请求。它缺少带有目标域名的 Host 标头,即它至少应该是这样的
GET /links HTTP/1.1
Host: www.example.com
除此之外,您的代码只是尝试读取数据,直到服务器关闭连接或达到内部缓冲区的大小。但是 HTTP/1.1 默认使用持久连接。因此,服务器可能会在发送响应后简单地保持连接打开,因为它期待您的下一个请求,这意味着您的程序将简单地阻止不做任何事情。
请注意,HTTP 远比看起来要复杂得多。如果您想实现它而不是使用现有的库,请研究实际标准。这就是标准的用途。
推荐阅读
- c - 浮点比较
- javascript - formData 为空(通过 XMLHttpRequest 上传时 - 纯 JavaScript)
- javascript - 将自定义域与 Firebase 动态链接结合使用
- sql-server - SQL Server 2008:文件的数据库恢复问题
- sql - 通过 SQL 查询获取随机 N 行,这将与不同部分的总行数成正比
- php - How to convert a mysql json field to a javascript Object with laravel?
- python - 使用opencv在鼻子和眼睛轴上旋转图像
- ruby - 继承前或后挂钩到子类
- json - Haskell 构建简单的 JSON 解析器
- oracle - 在 Oracle 中删除模式上的所有对象