socket-> recv () против <>? - PullRequest
       11

socket-> recv () против <>?

6 голосов
/ 08 апреля 2011

Я пытаюсь проработать небольшой проект по изучению Perl, который требует чтения 4-х целых чисел без знака из сокета.Я не мог прочитать более 1 целого числа, и, покопавшись, я нашел решение.Но мне НУЖНО понять, что я не сделал правильно (и через пару книг по Perl, perldocs и т. Д. Безрезультатно).

Пример 1. Вот код успешного решения ( оригинал), предположим, что сокет подключился успешно для обоих ниже:

{
  local $/ = \16; # make <> read in 16 bytes with one swoop.
  my @integers = unpack "IIII", <$sock>;
  print "numbers: @val\n";
}

Пример 2: Я попробовал это ниже.Если я распечатываю ввод перед распаковкой, я получаю только одно целое число:

my $input;
$sock->recv($input,16,0);
my @integers = unpack("IIII", $input);

Конкретные вопросы:

  1. В примере 1, что за черт "$ /"?И как это «изменить» <>, который я считал читать STDIN?
  2. В примере 2, есть ли какая-то причина, почему мой recv () не принимает более одного целого числа из сокета?Насколько я понимаю (per perldoc), параметр SIZE по умолчанию равен "bytes", а целые числа составляют 4 байта?

Любая помощь, указатели и т. Д. Приветствуются.Кстати, «учебный проект» - это overthewire.org - довольно крутой материал.

Ответы [ 3 ]

5 голосов
/ 09 апреля 2011

Является ли ваш сокет TCP или UDP?

recv - это процедура более низкого уровня, чем <> / readline.Он более или менее отображается непосредственно на системный вызов recv(2).Если данные сокета поступают в виде 4 4-байтовых пакетов, recv немедленно вернется, как только увидит первый пакет, даже если ему был предоставлен больший буфер.Если все 4 пакета прибывают до первого вызова recv(), то, получите ли вы все данные или только один фрагмент, зависит от того, будет ли это TCP или UDP.

Если вы используете TCP, есть вероятностьэти пакеты будут фрагментированы в полете.Это вряд ли произойдет с 16-байтовыми полезными нагрузками, но лучше не предполагать, что 16 байтов данных будут отображаться одновременно, даже если вы знаете, что сервер отправил их все сразу.Обычно сетевые приложения должны буферизовать входящие данные, или вы можете сделать это для perl, указав 16-байтовые записи с $/ = \16.

Еще одна возможность, которую я считаю более естественной, чем <>для этого вида использования ввода / вывода следует использовать функции read или sysread (или эквиваленты OO, которые определены в IO::Socket суперклассе IO::Handle).Они принимают аргумент длины, но, как и прежде, не следует предполагать, что весь буфер будет заполнен сразу.

2 голосов
/ 08 апреля 2011

Что касается 1)

Ну, <> принимает любые файловые дескрипторы, включая сокеты. Это соглашение , что вы можете оставить его пустым, и в этом случае предполагается какое-то нормальное поведение по умолчанию. См. perldoc perlop (поиск <> внутри).

И специальная переменная $/ является разделителем записей и по умолчанию имеет значение "\ n". Вы можете отменить его и прочитать весь файл одновременно (это называется slurping). См. perldoc perlvar для получения дополнительной информации (случай \number также имеется).

1 голос
/ 09 апреля 2011

read и readline (он же <>) ждут, пока запрошенное количество символов будет доступно, прежде чем вернуться. Он вернет только меньше символов в случае ошибки или EOF, и в этом случае при следующем чтении будет возвращена ошибка или EOF.

sysread возвращается, как только появятся некоторые символы, даже если запрошенное количество меньше.

Исходя из того, что вы говорите, recv похоже на sysread. Если вам нужно 16 символов, вам придется зацикливаться, пока у вас не будет 16 символов или вы не используете read или readline.

...