gpt4 book ai didi

在 C 中创建 HTTP 客户端以下载网页以供离线查看

转载 作者:塔克拉玛干 更新时间:2023-11-01 19:08:19 27 4
gpt4 key购买 nike

我正在创建一个 HTTP 客户端,它根据命令行参数下载网页。它接受参数,查找域名以获取 IP 地址,创建套接字,连接到服务器并发送 GET 请求并等待回复。这一切都很好,但是当我使用缓冲区和 while 循环阅读我的回复时,我也收到了一些不可读的字符。如果您运行代码并查看 html,您将在页面上到处看到不可读的字符。

我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
int socket_desc, i, bytes_read;
char server_reply[1024], ip[100], request[100];;
char *hostname = argv[1];
struct sockaddr_in server;
struct hostent *he;
struct in_addr **addr_list;
FILE *fp;

if ((he = gethostbyname(hostname)) == NULL) {
//gethostbyname failed
herror("gethostbyname\n");
return 1;
}

addr_list = (struct in_addr **) he->h_addr_list;

for(i = 0; addr_list[i] != NULL; i++) {
//Return the first one;
strcpy(ip , inet_ntoa(*addr_list[i]) );
}

//Create socket
socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if (socket_desc == -1) {
printf("Could not create socket!\n");
}

server.sin_addr.s_addr = inet_addr(ip);
server.sin_family = AF_INET;
server.sin_port = htons(80);

//Connect to remote server
if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0) {
printf("connect error!\n");
return 1;
}

printf("Connected...\n");

//Send some data
snprintf(request, 99, "GET / HTTP/1.1\r\n"
"Host: %s\r\n"
"\r\n\r\n", hostname
);

if (send(socket_desc, request, strlen(request), 0) < 0) {
puts("Send failed!\n");
return 1;
}
puts("Data Sent...\n");

//Receive a reply from the server

fp = fopen("/home/localusr/Desktop/ouput.html", "w+");

while (bytes_read = read(socket_desc, server_reply, sizeof(server_reply)) > 0) {
fputs(server_reply, fp);
memset(server_reply, 0, sizeof(server_reply));
}
do {
bytes_read = read(socket_desc, server_reply, sizeof(server_reply));
fputs(server_reply, fp);
memset(server_reply, 0, sizeof(server_reply));
} while (bytes_read > 0);

printf("reply received...\n");

fclose(fp);
close(socket_desc);

return 0;
}

对于缩进不佳的代码感到抱歉。非常感谢任何帮助。我正在使用 Ubuntu 机器并使用 gcc 编译我的代码。

编辑:

orb.ws.require.lib--> <script type="text/javascript">/*
be2

be2 不应该存在。 * 也得到 '@' 符号

最佳答案

编辑: 将我的评论放在这里:

请注意,例如www.bbc.co.uk 响应 header 显示“Transfer-Encoding: chunked”,这意味着每个 block 都有一个十六进制数字表示长度,后跟数据,然后是\r\n。

也就是说,根据您的示例:

be2\r\n => 0xbe2\r\n => 3042\r\n

“Here follows 3042 bytes”(在\r\n 之后又名 CRLF 或十六进制 0d0a)。

Example大块:

e\r\nStack Exchange
| | ||||||||||||||
| | +............+
| | |
| | +-------- 14 bytes
| +----------------- \r\n
+-------------------- 0x0e == 14 dec in hex

旧:


代替 memset 等,您可以通过以下方式正确终止读取字节:

while ( (bytes_read = read(socket_desc, server_reply, sizeof(server_reply) - 1)) > 0) {
server_reply[bytes_read] = 0x00;

在此之后,bytes_read 之外的任何内容都将被fputs


当您memset 整个缓冲区为0 读入整个缓冲区时 - memset 无效除非读取小于缓冲区大小。您只需在完整 (1024) 次读取和写入 1024 + 垃圾时覆盖所有零,直到第一个零。


read() 返回读取的字节数。通过将 server_reply[bytes_read] 设置为 0,您实际上终止了实际数据。把它变成一个 C 字符串。如果不将最后一个字节设置为零,fputs() 将在 bytes_read 之后继续输出垃圾,直到第一个零或崩溃。

换句话说; read() 最多读取 size 字节,不关心是否全为零字节。如果您告诉 read() 读取 356GiB 的数据,并且文件描述符提供 356GiB 的零(如 0x00 字节,而不是 ASCII 0)——这就是您得到的结果。

您的套接字不会以零终止传送。它像您的服务器一样将零字节作为数据的一部分传送。假设您以零字节传输图像或其他一些数据;换句话说:它不是 read() 获取的零终止字符串。

还要注意 sizeof 之后的 - 1 – 为空字节腾出空间。

fputs 然而 写入直到第一个终止空字节,但不将其包含在输出中(如果您正在写入缓冲的 string<,这通常是您想要的/strong>数据)。


示例:

char buf[8];

Char 未初始化且包含垃圾。例如它可以是:

buf[0] == 0x13
buf[1] == 0x0a
buf[2] == 0x00
buf[3] == 0x65
buf[4] == 0x78
buf[5] == 0xf3
buf[6] == 0x00
buf[7] == 0xaf

例如,除了 buf 你还有随机垃圾

buf[7+1] == 0xde
buf[7+2] == 0xa0
buf[7+3] == 0x33
buf[7+3] == 0x00

bytes_read = read(soc, buf, 8); soc delivers: 'ABCDEFG'

缓冲区现在是:

buf[0] == 0x41 (A)
buf[1] == 0x42 (B)
buf[2] == 0x43 (C)
buf[3] == 0x44 (D)
buf[4] == 0x45 (E)
buf[5] == 0x46 (F)
buf[6] == 0x47 (G)
buf[7] == 0xaf (H)

但是 buf[7] 之后的字节仍然是垃圾;并且您的 fputs() 将读取数据并将其传递到文件,直到第一个为零。

这就是为什么你会说:

bytes_read = read(soc, buf, 7);
buf[bytes_read] = 0x00;

现在我们只读A-G。最后一个字节设置为 0。

这里 fputs(buf, fh) 正在写直到第一个 \0,换句话说 ABCDEFG

如果服务器现在在下一次运行时只传送,比方说,只有两个字节:

buf[0] == 0x48 (H)
buf[1] == 0x5A (Z)

然后 bytes_read 将为 2 并且声明:

buf[bytes_read] = 0x00 ===> buf[2] = 0x00

这给了你

buf[0] == 0x48 (H)
buf[1] == 0x5A (Z)
buf[2] == 0x00 (0x00) <<--- nulled out
+---.
buf[3] == 0x44 (D) | \
buf[4] == 0x45 (E) | \
buf[5] == 0x46 (F) | }--->>> garbage from previous read.
buf[6] == 0x47 (G) | /
buf[7] == 0x00 (0x00) | /
+---/

这里 fputs(buf, fh) 正在写到第一个 \0,换句话说 HZ

关于在 C 中创建 HTTP 客户端以下载网页以供离线查看,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27421600/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com