字节排序 HTTP 客户端

Byte ordering HTTP Client

我编写了一个简单的 HTTP 客户端,可以从主机请求数据。

我正在使用 getaddrinfo(3)。通过 "GET / HTTP/1.1" 请求,我可以下载给定 http 主机的 HTML 页面。

这是我的部分代码:

struct addrinfo hints, *ai;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET; // Internet Protocol (IP) socket
hints.ai_socktype = SOCK_STREAM; // TCP 

int res = getaddrinfo("example.com", "http", &hints, &ai);
if (res != 0)
    ERROR_EXIT("getaddrinfo: %s\n", gai_strerror(res));

int sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sockfd < 0)
    ERROR_EXIT("socket: %s\n", strerror(errno));

if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0)
    ERROR_EXIT("connect: %s\n", strerror(errno));

FILE *sockfile = fdopen(sockfd, "r+");
if (sockfile == NULL)
    ERROR_EXIT("fdopen: %s\n", strerror(errno));

// send a GET request to the server:
if (fputs("GET / HTTP/1.1\r\n\r\n", sockfile) == EOF)
    ERROR_EXIT("fputs: %s\n", strerror(errno));
if (fflush(sockfile) == EOF)
    ERROR_EXIT("fflush: %s\n", strerror(errno));

char buf[1024];

// print the reply:
while (fgets(buf, sizeof(buf), sockfile) != NULL)
    fputs(buf, stdout);

fclose(sockfile);
return 0;

下载 HTML 页面工作正常,但下载 PNG 图片 "GET /image.png HTTP/1.1\r\n\r\n" 会得到如下结果:

???????ݹh??DHDZ?yW]%?9a??J?6F?Ѧ?E???ݐTd?US?:)??I??M,?-????=??U??&???Nr? ???б??? 
b??]??8?6+?;??i䂢d?G?WA?rԺ?H[??]?Z5????g?{8??i\?qAC?@c??v.?rb??'<?T?????O?z? 
q,yĜ?ŷZI???X??fM?l?Z??l:;M???ۦ?????c?\?W6+???o?}_???紈A??GvG?p??6{??{%?????0?{? 
%??ژ??l?$r<?????ft*'W?N?m߂Ҿ4??E?:^?#?&?%%
????Dw??Z?$??1?4?l%&2?f-5!?? ?E? 8...

我知道这是一个字节传输,我必须进行字节排序,但不知道从哪里开始。

我知道我需要对 PNG 图像使用 ntohl(3) 和 Big-endian 顺序。有人可以告诉我要查找的内容以及如何处理吗?

我是将此输出保存到 .png 文件然后执行字节顺序还是在创建 .png 文件之前执行?

在决定图像的顺序之前写出图像的字节没有多大意义。你的下一行是什么,fopen()?


如果你正在做像这样依赖于架构的事情,最好用 #if/#elif 来保护特定案例的部分,然后使用#else 发出 #error 诊断信息。 如果一切 应该 仍然有效,它可以只是 #warning... 但一定要放入警告。稍后,当它停止工作时。

您可以测试的配置宏应该包括 #ifdef __BIG_ENDIAN__#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__;你可以通过 'compiling' 和 -E -dD 查看还有什么可用的。 [会有很多; grep 是你的朋友]

哦,"big endian" 表示如果您按地址顺序读取字节 (a[0], a[1], a[2], ...),那么这一端的字节最多significant/highest'digit'。因此 "big-endian".

编辑:这也可能是一个问题...

FILE *sockfile = fdopen(sockfd, "r+");                     // "r+"
if (sockfile == NULL)
    ERROR_EXIT("fdopen: %s\n", strerror(errno));

if (fputs("GET / HTTP/1.1\r\n\r\n", sockfile) == EOF)      // fputs...

问题比 "byte order" 更复杂。

好消息是字节顺序可能无关紧要。您现在获得的代码应该可以很好地与服务器发送和接收文本字符串。

坏消息是,如果您想从服务器读取 二进制 数据,您需要以不同的方式连接。几个注意事项:

  • 听起来您可能不需要担心 "POST"、"PUT" ... 或除 "GET".

    以外的任何问题
  • 听起来您也不必担心 "MIME Types" 或 "uuencoding/decoding" - 您只需读取数据 as-is.

  • 您应该绝对从服务器的 HTTP 响应中读取 Content-TypeContent-Length headers。

  • 如果您正在读取二进制数据,也许最简单的方法就是在循环中调用 fgetc()。对字符串使用 fgets(),对 Content-Length 字节使用 fgetc() 来读取图像。

  • 您可能想要 fopen() 将图像字节写入文件。

  • 但是调用 fgets() 就不用担心 "byte order".

查看 here, here and here 示例。

'希望对您有所帮助...