Здравствуйте, ryglman, Вы писали:
R>Есть web-сервер, конкретно apache2.2.6, есть клиентское приложение шлет HTTP 1.1 R>POST запрос, с флагом Connnection: Close, сервер отвечает, и закрывает соеденение. R>Проблема в том что клинтское приложение получает ответ, вызовом блокирующей функции recv, R>recv(sock, pool, POOL_SIZE, 0), буфер pool заполняется, но функкция возращает 0, R>хотя может возращать -1 или же число записанных байт.
Извините, но Вы пишете полный бред. Если в стеке нет явного бага (а я очень сомневаюсь, что Вы его нашли) — если recv() вернул ноль, это значит, что соединение закрыто, данных больше не будет и содержимое буфера не имеет никакого значения в принципе.
Если Вы пытаетесь что-то читать из буфера, который был передан в recv() вернувшую 0 — Ваш дизайн программы грубо неверен и это работать не будет.
Если же Вы про ноль написали для красного словца и основная обработка идёт всё же в случае положительного возврата, то:
R>Вроде бы все выглядит логично, но если этот самый pool не заполнен нулями, а скажем заполнен cc(опкод инструкции int3, или же другой опкод напртимер неверная инструкция) в отладочных целях, то обработка полученного буфера как строки привеет к переполнению буфера.
(А при чём тут опкод? Вы что, сразу же пытаетесь исполнять код???)
Вы не имеете в общем случае никакого права обрабатывать данные из сети как "строку" (NUL-terminated, судя по стилю рассказа). Нету у Вас на этом уровне ещё никакой строки, забудьте. (Я уж молчу, что вообще NUL-terminated string — диверсия, за использование которой где-либо кроме одноразовых поделок и интерфейсов к Unix-style ядру надо откручивать голову и прочие выступающие части.) Использовать интерфейс строки с нулём можно только тогда, когда Вы убедились, что в принятых данных нет нигде NUL; в общем для HTTP (для тела ответа) на это полагаться нельзя.
Используйте или строки со счётчиком, или (мне значительно больше нравится такой стиль — с ним удобнее работать) пару указателей на начало обрабатываемой части и на позицию за последним символом.
Если же Вы каким-то святым духом однозначно уверены, что в буфере не будет NUL, и всё же намерены использовать диверсионный API типа strlen(), strcat() и тому подобное — есть простейший приём: буфер заранее готовится на один символ больше чем передаётся в recv(), а если recv() вернула положительное значение как признак того, что что-то приняла — сделать
buff[got] = '\0'
, где got — значение полученное из recv(). После этого — вытворяйте что хотите, лишь бы хватило места и не наезжали на соседние области (что с такими строками слишком просто сделать).
R>Приятнее было бы, выставить в ноль последний байт имеющий смысл что-то типа *pool[length] = '\0' и не трогать остальное простанство буфера, дело в том что далее будет очень много работа с тако строкой, а заполненность дальше последнего символа строки, т.е. 0, опкодами для отладки, тот же int3, может помоч отловить выход за границы буфера.
Чтобы получить кол-во прочитанных байт в вашем случае необходимо и достаточно читать данные побайтово — recv(..., ..., 1, ...) — и собирать их в собственный буфер.
Это самый простой вариант, однако при таком подходе не стоит расчитывать на высокую производительность.
Самый правильный вариант заключается в распарсивании HTTP-заголовка ответа сервера.
В частности, необходимо добраться до значения поля Content-Length, выделить необходимое кол-во байт и прочитать их в этот буфер.
Если клиентская система — Windows, тогда можно воспользоваться наиудобнейшей библиотекой WinINet.
Есть web-сервер, конкретно apache2.2.6, есть клиентское приложение шлет HTTP 1.1
POST запрос, с флагом Connnection: Close, сервер отвечает, и закрывает соеденение.
Проблема в том что клинтское приложение получает ответ, вызовом блокирующей функции recv,
recv(sock, pool, POOL_SIZE, 0), буфер pool заполняется, но функкция возращает 0,
хотя может возращать -1 или же число записанных байт.
Вроде бы все выглядит логично, но если этот самый pool не заполнен нулями, а скажем заполнен cc(опкод инструкции int3, или же другой опкод напртимер неверная инструкция) в отладочных целях, то обработка полученного буфера как строки привеет к переполнению буфера.
Не использовать отладочные примочки не хорошо, и заполнять 0, тоже не красиво, что делать, как сделать это красиво?
Здравствуйте, ryglman, Вы писали:
R>Не использовать отладочные примочки не хорошо, и заполнять 0, тоже не красиво, что делать, как сделать это красиво?
А разве "заполнить буфер нулями" — это не "стандартный принцип работы с буфером"?
Здравствуйте, The Lex, Вы писали:
TL>А разве "заполнить буфер нулями" — это не "стандартный принцип работы с буфером"?
Приятнее было бы, выставить в ноль последний байт имеющий смысл что-то типа *pool[length] = '\0' и не трогать остальное простанство буфера, дело в том что далее будет очень много работа с тако строкой, а заполненность дальше последнего символа строки, т.е. 0, опкодами для отладки, тот же int3, может помоч отловить выход за границы буфера.
Вобщем-то вопрос конечно был смешнйо согласен, он решился просто:
/**
* @param line
* @param stop
* @return
* char *
*/
char *getword(const char **line, char stop)
{
const char *pos = *line;
int len;
char *res;
while ((*pos != stop) && *pos) {
++pos;
}
#pragma warning(disable:4244)
len = pos — *line;
#pragma warning(default:4244)
res = (char *)malloc(len + 1);
memcpy(res, *line, len);
res[len] = 0;
if (stop) {
while (*pos == stop) {
++pos;
}
}
*line = pos;
return res;
}
while ((val = getword(&ppool2, '\n')) && strlen(val)) {
if (!strncmp(val, GOOD_TAG, sizeof(GOOD_TAG))) {
status = 1;
break;
}
}
Возник еще один — строка со счетчиком что это такое? Расскажите об этом приеме.
Я так понимаю это примерно такое:
struct string_t{
size_t size;
size_t count;
char data[1];
};
для удобства?
Здравствуйте, ryglman, Вы писали:
R>Здравствуйте, netch80
R>Вобщем-то вопрос конечно был смешнйо согласен, он решился просто:
... после чего идёт кусок кода, который ничего не читает из сети. Я это понять не могу.
R>Возник еще один — строка со счетчиком что это такое? Расскажите об этом приеме. R>Я так понимаю это примерно такое: R>struct string_t{ R> size_t size; R> size_t count; R> char data[1]; R>}; R>для удобства?
Ну примерно да, хотя я бы не использовал стиль с переменной длиной всей области со структурой в начале. Использовать отдельный указатель часто удобнее, к тому же тогда содержание строки можно, если не меняется, разделять между разными объектами. И главное даже не в этом, а в API. В случае C++ это std::string со всеми её методами.