recv windows, один байт на вызов, что? - PullRequest
2 голосов
/ 05 февраля 2010

C ++

#define BUF_LEN 1024

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

output = new char[BUF_LEN];
bytes_recv = recv(cli, output, BUF_LEN, 0);
output[bytes_recv] = '\0';

Есть идеи, как заставить его получать больше байтов?

РЕДАКТИРОВАТЬ: клиент подключается через Telnet.

Ответы [ 3 ]

5 голосов
/ 05 февраля 2010

При работе в сети следует помнить, что вы сможете прочитать столько данных, сколько было получено. Поскольку ваш код запрашивает 1024 байта, а вы читаете только 1, то был получен только 1 байт.

Поскольку вы используете клиент telnet, похоже, что вы настроили его в символьном режиме. В этом режиме, как только вы введете символ, он будет отправлен.

Попробуйте перенастроить ваш клиент telnet в режиме линии. В линейном режиме клиент telnet будет ждать, пока вы не нажмете return, прежде чем отправит всю строку.

На моем клиенте telnet. Для этого сначала введите ctrl-], чтобы перейти к приглашению telnet, а затем введите «mode line» для настройки telnet в режиме линии.

Обновление

Если подумать, это действительно очень хорошая проблема.

В реальном мире ваши данные могут быть фрагментированы неожиданным образом. Клиент может сделать один вызов send () из N байтов, но данные могут не поступить в одном пакете. Если ваш код может обрабатывать поступающие байты 1 на 1, то вы знаете, что он будет работать независимо от того, как поступают данные.

Что вам нужно сделать, это убедиться, что вы накапливаете свои данные за несколько приемов. После того, как ваш вызов recv вернется, вы должны добавить данные в буфер. Что-то вроде:

char *accumulate_buffer = new char[BUF_LEN];
size_t accumulate_buffer_len = 0;

...

bytes_recv = recv(fd,
                  accumulate_buffer + accumulate_buffer_len,
                  BUF_LEN - accumulate_buffer_len,
                  0);
if (bytes_recv > 0)
    accumulate_buffer_len += bytes_recv;

if (can_handle_data(accumulate_buffer, accumulate_buffer_len))
{
    handle_data(accumulate_buffer, accumulate_buffer_len);
    accumulate_buffer_len = 0;
}

Этот код продолжает накапливать recv в буфер, пока не будет достаточно данных для обработки. После обработки данных вы сбрасываете длину до 0 и начинаете накапливать заново.

1 голос
/ 05 февраля 2010

Сначала в этой строке:

output[bytes_recv] = '\0';

Вам нужно сначала проверить, если bytes_recv < 0, прежде чем сделать это, потому что у вас может быть ошибка. И так, как работает ваш код в настоящее время, вы будете просто случайным образом топать какой-то случайный кусок памяти (вероятно, байт непосредственно перед буфером).

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

Наконец, у потоковых сокетов есть модель, которая представляет собой очень длинный кусок ленты с множеством штампованных букв. Нет никаких обещаний, что лента будет двигаться с какой-то определенной скоростью. Когда вы звоните recv, вы говорите: «Пожалуйста, дайте мне столько писем с ленты, сколько у вас до сих пор, до такого количества». Вы можете получить столько, сколько просите, вы можете получить только 1. Никаких обещаний. Неважно, как другая сторона выплевывает биты ленты, лента проходит через чрезвычайно сложную связку передач, и вы просто не представляете, сколько букв будет проходить в любой момент времени.

Если вы заботитесь об определенных группах символов, вы должны поместить вещи в поток (на ленту), сообщая, где эти единицы начинаются и / или заканчиваются. Есть много способов сделать это. Сам Telnet использует несколько разных в разных обстоятельствах.

А на принимающей стороне вы должны искать эти маркеры и складывать последовательности символов, которые вы хотите рассматривать как единое целое, самостоятельно.

Итак, если вы хотите прочитать строку, вы должны читать, пока не получите '\ n'. Если вы пытаетесь читать 1024 байта за раз, вы должны принять во внимание, что '\ n' может оказаться в середине вашего буфера, и поэтому ваш буфер может содержать строку, которую вы хотите, и часть следующей строки. Он может даже содержать несколько строк. Единственное обещание - вы не получите больше символов, чем просили.

0 голосов
/ 05 февраля 2010

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

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