所以,我在 C 語言中有一個簡單的程式,它試圖發出 HTTP 請求:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void err(const char *msg) {
fprintf(stderr, "[ERROR] %s\n", msg);
exit(1);
}
int main(int argc,char *argv[])
{
char *host;
int port;
char *request;
host = "api.ipify.org";
port = 80;
request = "GET / HTTP/1.1\r\nHost: api.ipify.org\r\n\r\n";
struct hostent *server;
struct sockaddr_in serv_addr;
int sockfd, bytes, sent, received, total;
char response[4096];
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) err("Couldn't open socket");
server = gethostbyname(host);
if (server == NULL) err("No such host");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length);
/* connect the socket */
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) err("Couldn't connect");
/* send the request */
total = strlen(request);
sent = 0;
while (sent < total) {
bytes = write(sockfd, request sent, total - sent);
if (bytes < 0) err("Couldn't send request");
if (bytes == 0) break;
sent = bytes;
}
/* receive the response */
memset(response, 0, sizeof(response));
total = sizeof(response) - 1;
received = 0;
while (received < total) {
bytes = read(sockfd, response received, total - received);
if (bytes < 0) err("Couldn't receive response");
if (bytes == 0) break;
received = bytes;
}
/*
* if the number of received bytes is the total size of the
* array then we have run out of space to store the response
* and it hasn't all arrived yet - so that's a bad thing
*/
if (received == total) err("Couldn't store response");
/* close the socket */
close(sockfd);
/* process response */
printf("Response:\n%s\n",response);
return 0;
}
但是,當我編譯并運行它時,它會做它應該做的事情,但這需要很長時間。使用命令運行它time表明它需要大約 1m 0.3s 才能執行。如果我注釋掉read函式呼叫,執行時間會回到 0.3 秒。這意味著由于某種原因,它將我的程式延遲了 1 分鐘。
我嘗試printf在 main 函式的開頭放置 a ,但是直到 1 分鐘過去后才呼叫它。
為什么整個主要功能被一個功能延遲,我該如何解決這個問題?
uj5u.com熱心網友回復:
首先,您應該在標題中包含一個欄位,如下所示:
Content-length: 0\r\n
請求確實是請求,請求不包含正文GET也是正確的。GET但是這個要求不是強制性的,如果你愿意,你可以發送一個正文(而服務器被要求忽略它,對于一個GET請求),發送一個非空的正文是不被禁止的。您應該發送一個Content-length欄位。
其次,由于您沒有關閉連接,也沒有關閉它,并且當您使用 版本1.1時HTTP,服務器正在等待更多內容的到來(新請求或第一個GET方法的主體)。閱讀 RFC 檔案RFC2616以獲取有關1.1連接模型的資訊。
更改以下行后
while (received < total) {
bytes = read(sockfd, response received, total - received);
if (bytes < 0) err("Couldn't receive response");
if (bytes == 0) break;
received = bytes;
}
進入
while (received < total) {
bytes = read(sockfd, response received, total - received);
if (bytes < 0) err("Couldn't receive response");
if (bytes == 0) break;
write(1, response received, bytes); /* <<< this line added */
received = bytes;
}
要查看我們收到的內容,我可以觀察到服務器向您發送了一個簡短的回應:
$ http
HTTP/1.1 200 OK
Server: Cowboy
Connection: keep-alive
Content-Type: text/plain
Vary: Origin
Date: Mon, 21 Feb 2022 21:39:22 GMT
Content-Length: 14
Via: 1.1 vegur
82.181.193.234_ (<-- cursor remains there, as the last _ char)
并且確實一直在等待下一個請求(如 中指定的HTTP/1.1,用于保持活動連接) 最后,服務器超時,并關閉連接。
You can switch to HTTP/1.0, as keep alive connections are not supported by HTTP/1.0, and will see how the connection is closed by the server immediately after the request. For a good interaction with the server, you should parse the headers of the response as you receive them, and then interpret the Content-length: sent by the server (or the chunks, in case of a Content-encoding: chunked content) to detect when the response is finished. The reason is the same as for the request. It is used by the other side in order to reuse the connection for the next request, and to detect where the request/response ends. In this case, the server sends a
Content-Length: 14\r\n
so when you receive the two consecutive CRLFs, you should read 14 bytes and stop there, in order to continue reading from that point the response to the next request.
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/434928.html
