Perl client socket - >recv() Vs когда серверный сокет вызывает send несколько раз


У меня есть серверный сокет perl, который возвращает поля по одному, вызывая send () на клиентском сокете.

У меня нет проблем с чтением всех полей на стороне клиента, если код выглядит следующим образом:

while ($response = <$sock>) {
print "$response";
last if $response eq "END_OF_REQUEST";
}

Но если код на стороне клиента похож на приведенный ниже, он входит в цикл и не работает:

while(1) {      
$sock->recv($response, 1);
print "$responsen";    
last if $response eq "END_OF_REQUEST" ;
}

Я согласен, что могу объединить все поля и вызвать только один send на стороне сервера. Но мне интересно знать, что не так со 2-м подходом. Не меняется длина arg recv во 2-м подходе делает трюк?

Я вроде как начал получать практический опыт непосредственно без должных теоретических знаний о розетках. Спасибо за ваше терпение.

1 3

1 ответ:

Аргумент length для recv() - этомаксимальная длина сообщения, которое вы хотите получить, и recv() никогда не запишет в буфер больше, чем это количество символов. (То, что происходит с остальной частью сообщения, зависит от типа сокета; для потоковых сокетов он будет доступен для следующего вызова recv(), в то время как для сокетов дейтаграмм он просто выбрасывается.)

Таким образом, ваш $sock->recv($response, 1); запишет в $response не более одного символа. Очевидно, что односимвольная строка может никогда не равны "END_OF_REQUEST". Простое решение состоит в том, чтобы передать достаточно большую максимальную длину в recv(), чтобы ваше сообщение не было усечено.

Вот простая демонстрация:

use strict;
use warnings;
use IO::Socket;

my ($rd, $wr) = IO::Socket->socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC)
    or die "socketpair: $!";
defined $wr->send("Hello, world!") or die "send: $!";
my $buf;
do {
    defined $rd->recv($buf, 9) or die "recv: $!";
    print qq(received: "$buf"\n);
} while ($buf !~ /!/);

Это выведет:

received: "Hello, wo"
received: "rld!"