Порядок байтов HTTP-клиент

Я написал простой 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?

Для начала вы не можем используете fgets() для чтения двоичных данных. ПРЕДЛОЖЕНИЯ: 1) Если вы можете использовать другой язык и/или библиотеку HTTP более высокого уровня, вам, вероятно, следует это сделать. 2) В противном случае, Google для некоторых примеров C-языка/сокета. 3) Пожалуйста, отправьте ответ с тем, что вы найдете, и последующими вопросами, которые у вас могут возникнуть. Как только вы найдете альтернативу fgets().

paulsm4 10.04.2019 19:59

@ paulsm4 Здравствуйте, мне нужно использовать C. Все примеры сокетов, которые я нашел в Интернете, слишком просты. Например, я могу загрузить этот .png и открыть его с помощью fopen, а затем прочитать данные с помощью rb. Будет ли это хорошим началом?

cheshire 10.04.2019 20:06

Вопрос: У вас получилось? Если нет, В: Есть ли причина, по которой вы должны использовать «C»? В: Можно ли использовать библиотеки C, такие как libCurl?

paulsm4 12.04.2019 20:33
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
160
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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


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

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

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

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...
Ответ принят как подходящий

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

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

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

  • Похоже, вам, вероятно, не нужно беспокоиться о «POST», «PUT»… или о чем-либо, кроме «GET».

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

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

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

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

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

Посмотрите примеры здесь, здесь и здесь.

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

Другие вопросы по теме