Заказ байтов HTTP-клиента - PullRequest
0 голосов
/ 10 апреля 2019

Я написал простой HTTP-клиент, который может запрашивать данные с хоста.

Я использую getaddrinfo (3).По запросу «GET / HTTP / 1.1» я могу загрузить HTML-страницу данного http-хоста.

Вот часть моего кода:

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...

Я понимаю, что это передача байтов, и что я должен делать упорядочивание байтов, но не знаю, с чего начать.

Я знаю, что мне нужно использовать ntohl (3) и порядок с прямым порядком байтов для изображений PNG.Кто-то может дать мне указания, что искать и как к этому подойти?

Сохраняю ли я эти выходные данные в файл .png, а затем делаю байтовый порядок или я делаю это перед созданием файла .png?

Ответы [ 2 ]

0 голосов
/ 10 апреля 2019

Проблема более сложная, чем просто "порядок байтов".

Хорошая новость заключается в том, что порядок байтов , вероятно, не имеет значения .Код, который вы получили сейчас, должен нормально работать, отправляя и получая текстовые строки с сервера.

Плохая новость заключается в том, что вам нужно подключиться по-другому , если вы хотите прочитать двоичные данные с сервера.Несколько соображений:

  • Звучит так, что вам, вероятно, не нужно беспокоиться о "POST", "PUT" ... или о чем угодно, кроме "GET".

  • Звучит так, будто вам не нужно беспокоиться о «типах MIME» или «uuencoding / decoding» - вы просто будете читать данные как есть.

  • Вы должны определенно прочитать заголовки Content-Type и Content-Length из HTTP-ответа сервера.

  • Возможно, самый простой подход - просто позвонить fgetc()в цикле, если вы читаете двоичные данные.Используйте fgets() для строк и fgetc() для Content-Length байтов для чтения изображения.

  • Возможно, вы захотите сделать fopen() для записи байтов изображения вфайл.

  • Но вызов fgets () избавляет от необходимости беспокоиться о «порядке следования байтов».

Смотрите здесь , здесь и здесь для примеров.

'Надеюсь, это поможет ...

0 голосов
/ 10 апреля 2019

Не имеет большого смысла записывать байты изображения, прежде чем решить, в каком порядке они должны быть. Какой будет следующая строка, fopen()?


Есливы делаете что-то зависящее от архитектуры, как это, лучше всего защищать разделы для конкретного случая с помощью #if / #elif и использовать #else для выдачи #error с диагностическим сообщением.Если все должно по-прежнему работать, это может быть просто #warning ... но вставьте предупреждение. Позже, когда оно перестанет работать.

Макросы конфигурации, которые вы можете протестировать, должны включать #ifdef __BIG_ENDIAN__ и #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__;вы можете увидеть, что еще доступно, 'скомпилировав' с -E -dD. [будет много;grep - ваш друг]

О, а "big endian" означает, что вы читаете байты в порядке адресов (a [0], a [1], a [2],...), тогда байт на этом конце является самой значимой / старшей «цифрой».Следовательно, "big-endian".

edit: это также может быть проблемой ...

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...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...