Я написал простой 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?
@ paulsm4 Здравствуйте, мне нужно использовать C. Все примеры сокетов, которые я нашел в Интернете, слишком просты. Например, я могу загрузить этот .png и открыть его с помощью fopen
, а затем прочитать данные с помощью rb
. Будет ли это хорошим началом?
Вопрос: У вас получилось? Если нет, В: Есть ли причина, по которой вы должны использовать «C»? В: Можно ли использовать библиотеки C, такие как libCurl?
Не имеет большого смысла записывать байты изображения, прежде чем решить, в каком порядке они должны быть. Какой будет ваша следующая строка, 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() избавляет от необходимости беспокоиться о «порядке байтов».
Посмотрите примеры здесь, здесь и здесь.
'Надеюсь, это поможет...
Для начала вы не можем используете
fgets()
для чтения двоичных данных. ПРЕДЛОЖЕНИЯ: 1) Если вы можете использовать другой язык и/или библиотеку HTTP более высокого уровня, вам, вероятно, следует это сделать. 2) В противном случае, Google для некоторых примеров C-языка/сокета. 3) Пожалуйста, отправьте ответ с тем, что вы найдете, и последующими вопросами, которые у вас могут возникнуть. Как только вы найдете альтернативуfgets()
.