Почему в этом примере AnyEvent::Handle не вызывается on_eof?
Это мой простой сервер. Когда я запускаю его и подключаюсь к нему через telnet (порт 5222), и когда telnet завершает соединение, почему не вызывается моя функция on_eof? Т.е. почему не строка "КАТАСТРОФА!!!" печататься?
#!/usr/bin/perl
use v5.18;
use warnings;
use EV;
use AnyEvent;
use AnyEvent::Socket;
use AnyEvent::Handle;
our $hdl;
my $server = tcp_server undef, 5222, sub {
my ($fh) = @_;
$hdl = AnyEvent::Handle->new(fh => $fh);
$hdl->on_eof(sub {
my ($handle) = @_;
say "CATASTROPHE!!!";
});
};
EV::run;
1 ответ
tl;dr: без попытки чтения из сокета, EOF не может быть обнаружен. Используйте ->on_eof или ->push_read.
Длинная версия:
Пример не пытается что-либо прочитать из дескриптора, и именно поэтому AnyEvent::Handle не пытается читать данные. Без попытки чтения данных он не может обнаружить EOF (следствие API POSIX).
Это поведение описано только косвенно в описании методов start_read/stop_read:
Обратите внимание, что AnyEvent::Handle автоматически "start_read" для вас при изменении обратного вызова "on_read" или push/unshift чтения обратного вызова, и он будет автоматически "stop_read" для вас, когда не установлено ни "on_read", ни чтения запросы в очереди.
Причина, по которой он ведет себя так, заключается в том, что в программе, основанной на событиях, может быть любое количество времени между чтением данных (выполненных внутри) и постановкой в очередь обратного вызова чтения. Поскольку получение данных, которые не являются ожидаемыми, является ошибкой (и если не сделать так, чтобы ошибка могла переполнить буфер чтения, вызывая ошибку), должен быть какой-то способ избежать этих ошибок.
Не чтение данных, когда ничего не запрашивается, - это автоматический способ избежать ложных ошибок, вызванных тем, что программа не "достаточно быстра" для обработки данных: AnyEvent::Handle просто не читает ничего из сокета, пока программа не примет решение о что делать с данными.
В вашем довольно нетипичном примере вы ничего не делаете с сокетом. Чтобы обнаружить on_eof, вы можете вызвать ->start_read, но это вряд ли будет полезно в реальных программах.