Сокет: неверная длина, возвращаемая функцией read () - PullRequest
1 голос
/ 13 июля 2009

Я довольно новичок в программировании сокетов. У меня есть вызов функции, похожий на:

len = read(FD, buf, 1500);

[который отвечает за чтение данных из соединения telnet]

printf в следующей строке показывает, что длина buf> 300 символов, но (int) len дает только 89! Из-за этого весь дальнейший анализ возвращаемой строки завершается неудачей ..

Я прочитал много вопросов о чтении асинхронного сокета, возвращающего меньше требуемых данных, но в приведенном выше случае он возвращает достаточное количество данных, но указанная длина неверна [возвращаемая строка всегда одинакова, а длина всегда одинакова неправильное значение] ...

Также вышеуказанная функция работает правильно, когда возвращаемая строка мала (обычно в диапазоне 100 символов)

Любые указатели были бы чрезвычайно полезны!

- Ashwin

Ответы [ 4 ]

2 голосов
/ 13 июля 2009

Вы можете обнулить буфер со смещением чтения, используя:

buf[len] = 0;

Печатный вызов должен быть в порядке.

1 голос
/ 13 июля 2009

но в приведенном выше случае он возвращает достаточное количество данных, но указанная длина неверна

Нет, вы не правы в этом. Возвращает то, что говорит, возвращается, 89 байт. Проблема в том, что эти 89 байтов не содержат нулевого терминатора, так что, когда вы printf буфер, он продолжает работать, печатая то, что уже было в оставшейся части буфера до того, как произошел ваш read.

То, что вы должны делать (но смотрите предостережение ниже), выглядит примерно так:

len = read(FD, buf, 1500);
printf ("%*.*s\n", len, len, buf);

, чтобы гарантировать, что вы не печатаете за пределами буфера.

То, что вы видите, эквивалентно:

char buff[500];
strcpy (buff, "Hello there");
memcpy (buff, "Goodbye", 7);
printf ("%s", buff);

Поскольку вы не передаете нуль-символ в memcpy, у вас остается следующий буфер:

               +---+---+---+---+---+---+---+---+---+---+---+---+
After sprintf: | H | e | l | l | o |   | t | h | e | r | e | \0|
               +---+---+---+---+---+---+---+---+---+---+---+---+
After memcpy : | G | o | o | d | b | y | e | h | e | r | e | \0|
               +---+---+---+---+---+---+---+---+---+---+---+---+

дает строку "Goodbyehere".

Оговорка:

Если в вашем потоке данных есть нулевые символы, то printf не будет работать, так как остановится на первом найденном нулевом символе. Функция read считывает двоичные данные из файлового дескриптора, и ей не нужно останавливаться на первой новой строке или нулевом символе.

Это было бы эквивалентно:

char buff[500];
strcpy (buff, "Hello there");
memcpy (buff, "Go\0dbye", 8);
printf ("%s", buff);

               +---+---+---+---+---+---+---+---+---+---+---+---+
After sprintf: | H | e | l | l | o |   | t | h | e | r | e | \0|
               +---+---+---+---+---+---+---+---+---+---+---+---+
After memcpy : | G | o | \0| d | b | y | e | \0| e | r | e | \0|
               +---+---+---+---+---+---+---+---+---+---+---+---+

дает строку "Go".

Если вы действительно хотите обработать строку с нулем или новой строкой в ​​том, что является двоичным каналом, следующее (псевдокод) является одним из способов сделать это:

while true:
    while buffer has no terminator character:
        read some more data into buffer, break on error or end-of-file.
    break on error or end-of-file.
    while buffer has at least one terminator character:
        process data up to first terminator character.
        remove that section from buffer.

Это процесс, который считывает данные до тех пор, пока у вас есть хотя бы одна «единица работы», а затем обрабатывает эти единицы работы до тех пор, пока у вас не останется полная единица работы.

1 голос
/ 13 июля 2009

Обычно для асинхронных сокетов вы должны читать, пока не будет получено желаемое количество байтов. Это означает, что вы должны управлять буферами. (т.е. увеличить указатель буфера в соответствии с полученными байтами и т. д.)

Наблюдения, которые у вас есть о буфере, имеющем правильный объем данных, но сообщающем о неправильном размере, вероятно, вызваны устаревшими данными из предыдущего запуска. Для подтверждения вы можете очистить буфер перед каждым запуском.

0 голосов
/ 13 июля 2009

read () пытается прочитать до 1500 байт из файлового дескриптора FD в буфер, начиная с buf. В случае успеха возвращается количество прочитанных байтов. Не является ошибкой, если это число меньше числа запрошенных байтов ; это может произойти, например, потому что на самом деле сейчас доступно меньше байтов (возможно, потому что мы были близки к концу файла

Как правило, вам нужно вызвать чтение в цикле.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...