Модераторы: korob2001, ginnie
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> AnyEvent::Handle, виснет push_read, помогите, плз!!! 
V
    Опции темы
shootnix
  Дата 21.11.2011, 13:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 108
Регистрация: 3.9.2005
Где: Казахстан

Репутация: 2
Всего: 2



Привет всем. 
У меня возникла довольно глупая проблема, не могу понять, где порылась собака.  smile 
Задача простая: подключиться к серверу через AnyEvent::Socket, чтобы понадежнее держать соединения + всякие плюшки из коробки, выбрал AnyEvent::Handler. Такой код в итоге получается пока:

Код

sub socket_call {
    my ($msg, $host, $port) = @_;
    
    return unless $msg;
    
    $host ||= 'localhost';
    $port ||= 12345;
    
    my $cv = AnyEvent->condvar;
    say 'Try to connect';
    
    tcp_connect $host, $port, sub {
    my ($fh) = @_ or $cv->send;
    
    say 'Connecting...';
    
    my $handle;
    $handle = AnyEvent::Handle->new(
        fh => $fh,
        poll => 'rw',
        on_error => sub {
        say 'Error!';
        shift->destroy;
        $cv->send;
        },
        on_eof => sub {
        say 'EOF!';
        shift->destroy;
        $cv->send;
        },
    );
    
    say 'Try to write';
    $handle->push_write($msg);
    
    say 'Try to read';
    $handle->push_read( json => sub {
        my ($handle, $line) = @_;
        
        say 'line: ' . $line;
        $cv->send;
    });
    };
    
    $cv->recv;
    
    return $res;
}
 

На экране наблюдаю такое:

Код

Try to connect
Connecting...
Try to write
Try to read


скрипт висит и явно чего-то еще ждет, чего — не могу понять. То ли коннект теряется, то ли еще какая лажа, в общем, плиз, хелп!

UPD: Кое-что еще о поведении программы.
1. Сервер получает нужную строку, пытается ее отдать обратно.
2. Скрипт строку в ответ не получает, просто висит и чего-то ждет.
3. Если при зависшем скрипте остановить сервер, ничего не изменится, скрипт продолжит висеть. 

Я делаю вывод, что происходит какая-то блокировка, мб, сокета? Пробую push_write много раз подряд — все гуд, на чтении — такой глюк.

Это сообщение отредактировал(а) shootnix - 21.11.2011, 14:23
PM WWW ICQ   Вверх
Pfailed
Дата 21.11.2011, 14:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 19.7.2009

Репутация: 22
Всего: 39



У AnyEvent::Handle есть опция poll?
Уверены что сервер отдает валидный json? Может начать с простого и попытаться прочитать просто строку?



--------------------
PM MAIL   Вверх
shootnix
Дата 21.11.2011, 19:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 108
Регистрация: 3.9.2005
Где: Казахстан

Репутация: 2
Всего: 2



Валиный/невалидный — не имеет значения, не работает и все тут. 
Пробую:
Код

push_read(line => sub {});

Та же песня…
PM WWW ICQ   Вверх
shootnix
Дата 21.11.2011, 20:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 108
Регистрация: 3.9.2005
Где: Казахстан

Репутация: 2
Всего: 2



Вообще, сдается мне, не срабатывает событие чтения. Как запустить?
PM WWW ICQ   Вверх
Pfailed
Дата 21.11.2011, 20:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 19.7.2009

Репутация: 22
Всего: 39



Вы не сохраняете ссылку на $handle, объект попросту уничтожается.
Замените например shift->destroy на $handle->destroy


--------------------
PM MAIL   Вверх
shootnix
Дата 21.11.2011, 20:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 108
Регистрация: 3.9.2005
Где: Казахстан

Репутация: 2
Всего: 2



Цитата(Pfailed @ 21.11.2011,  20:05)
Вы не сохраняете ссылку на $handle, объект попросту уничтожается.
Замените например shift->destroy на $handle->destroy

Спасибо, конечно, но в документации именно что написано:
Код

$_[0]->destroy;

Думаю, это не случайно. 
PM WWW ICQ   Вверх
Pfailed
Дата 21.11.2011, 20:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 19.7.2009

Репутация: 22
Всего: 39



Проблема то решена или в верю-неверю поупражняемся? Могу лишь посоветовать перечитать документацию еще раз.


--------------------
PM MAIL   Вверх
shootnix
Дата 21.11.2011, 20:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 108
Регистрация: 3.9.2005
Где: Казахстан

Репутация: 2
Всего: 2



Проблема не решена. На текущий момент код такой (не весь):
Код

tcp_connect $host, $port, sub {
    my ($fh) = @_ or $cv->send;
    
    say 'Connecting...';
    
    my $handle;
    $handle = AnyEvent::Handle->new(
        fh => $fh,
        on_error => sub {
        say 'Error!';
        shift->destroy;
        $cv->send;
        },
        on_eof => sub {
        say 'EOF!';
        shift->destroy;
        $cv->send;
        },
    );
    
    say 'Try to write';
    $handle->push_write($msg);
    
        say 'Try to read';
    $handle->push_read(
        line => sub {
        my ($h, $line) = @_;
        
        say 'Got line: ' . $line;
        $cv->send($line);
        }
    );
    };
    
    my ($result) = $cv->recv;

Вот эту строчку «say 'Got line: ' . $line;» я не вижу, замирает на «say 'Try to read';».
Обработчики on_error и on_eof отрабатывают корректно, дело явно не в шифтах.
PM WWW ICQ   Вверх
Pfailed
Дата 21.11.2011, 21:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 19.7.2009

Репутация: 22
Всего: 39



server.pl
Код

use strict;
use IO::Socket;

my $serv = IO::Socket::INET->new(LocalPort => 1111, Listen => 1)
    or die $@;

while (1) {
    my $client = $serv->accept();
    unless ($client) {
        warn $!;
        next;
    }
    warn 'client accepted';
    
    eval {
        $client->sysread(my $buf, 1024) or die "read failed: $!";
        warn $buf, ' from the client';
        $client->syswrite(scalar(reverse $buf)."\n") or die "write failed: $!";
    };
    if ($@) {
        warn $@;
    }
    
    $client->close();
    warn 'client connection closed';
}


client.pl
Код

use strict;
use v5.10;
use AnyEvent;
use AnyEvent::Socket;
use AnyEvent::Handle;

socket_call('To be, or not to be', 'localhost', 1111);

sub socket_call {
    my ($msg, $host, $port) = @_;
    
    return unless $msg;
    
    $host ||= 'localhost';
    $port ||= 12345;
    
    my $cv = AnyEvent->condvar;
    say 'Try to connect';
    
    tcp_connect $host, $port, sub {
    my ($fh) = @_ or $cv->send;
    
    say 'Connecting...';
    
    my $handle;
    $handle = AnyEvent::Handle->new(
        fh => $fh,
        on_error => sub {
        say 'Error!';
        shift->destroy;
        $cv->send;
        },
        on_eof => sub {
        say 'EOF!';
        $handle->destroy;
        $cv->send;
        },
    );
    
    say 'Try to write';
    $handle->push_write($msg);
    
        say 'Try to read';
    $handle->push_read(
        line => sub {
        my ($h, $line) = @_;
        
        say 'Got line: ' . $line;
        $cv->send($line);
        }
    );
    };
    
    my ($result) = $cv->recv;
}


УМВР. ЧЯДНТ? Заметьте,  с shift не работает.


--------------------
PM MAIL   Вверх
shootnix
Дата 21.11.2011, 21:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 108
Регистрация: 3.9.2005
Где: Казахстан

Репутация: 2
Всего: 2



Хм, кстати да, работает отменно, если сервер однопоточный. У меня — мультиплексный, вероятно, тут есть свои тонкости… Пошел искать, спасибо за помощь. 
PM WWW ICQ   Вверх
shootnix
Дата 21.11.2011, 23:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 108
Регистрация: 3.9.2005
Где: Казахстан

Репутация: 2
Всего: 2



Почти разобрался =) 
Скорее всего, ответ от сервера шлется не туда, т.е., код навроде этого не работает (на стороне сервера):
Код

$handle->push_write("Hello from server!");

Кто знает, как писать ответы сервера в случае с AnyEvent? AnyEvent::Handle? Помогите, пожалуйста, у меня пока опыта маловато с этим… 
PM WWW ICQ   Вверх
Pfailed
Дата 22.11.2011, 05:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 19.7.2009

Репутация: 22
Всего: 39



Код сервера покажите.


--------------------
PM MAIL   Вверх
shootnix
Дата 22.11.2011, 09:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 108
Регистрация: 3.9.2005
Где: Казахстан

Репутация: 2
Всего: 2



У меня, на самом деле, несколько имплементаций, но цель моя — сделать на том и на другом конце AnyEvent-решения, используя AnyEvent::Handle — не достигнута. Пытаюсь сделать по образу и подобию того, что есть в интернетах:

Код

my @clients;

tcp_server undef, 12345, sub {
    my ($fh) = @_ or die $!;
    my $h = AnyEvent::Handle->new( fh => $fh );

    $h->on_read(sub {
        shift->push_read( line => sub {
            my ($h, $line) = @_;
        
        say 'line: ' . $line;

            my $client = $clients[ fileno($fh) ];

            $line .= '!';
            $client->{handle}->push_write($line);
        });
    });

    $h->on_error(sub {
        my ($h, $fatal, $msg) = @_;
        $h->destroy;
    });

    $clients[ fileno($fh) ] = {
        name   => undef,
        handle => $h,
    };
};

AE::cv->wait;


Подключаюсь телнетом, все гуд, скриптом — данные не ходят ни туда, ни обратно. К слову, предыдущий сервер на основе IO::Select работал норм, данные принимал, но клиент не мог их поймать. Вот примерный код его:

Код

my $port = 12345;
my $server = IO::Socket->new(
    Domain => PF_INET,
    Proto => 'tcp',
    LocalPort => $port,
    Listen => SOMAXCONN,
);
die 'Cannot bind: ' . $! unless $server;

my $selector = IO::Select->new($server);
$SIG{PIPE} = 'IGNORE';

say 'Multiplex server started on port ' . $port;
while ( my @clients = $selector->can_read() ) {
    for my $client (@clients) {
    if ( $client == $server ) {
        ### Новый коннект
        my $new_client = $server->accept;
        #syswrite $new_client, 'hello';
        
        my $port = $new_client->peerport;
        my $name = $new_client->peerhost;
        say "New client $port:$name";
        $selector->add($new_client);
    }
    else {
        ### Клиент уже подключился ранее
        my $port = $client->peerport;
        my $name = $client->peerhost;
        my $message;
        if ( sysread $client, $message, 1024 ) {
        say "Client $name:$port sent: $message";
        
        }
        else {
        $selector->remove($client);
        $client->shutdown(SHUT_RDWR);
        say "Client disconnected";
        }
    }
    }
}



Это сообщение отредактировал(а) shootnix - 22.11.2011, 09:57
PM WWW ICQ   Вверх
DurRandir
Дата 22.11.2011, 15:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 335
Регистрация: 27.9.2009

Репутация: 14
Всего: 17



Вы так и не привели в одном посте код клиента и сервера) Но проблема в том, что читаете вы через push_read в line-mode что клиентом, что сервером. А этот режим отбрасывает разделитель строк, и возвращает вам строчку без него. Потом вы её (не добавляя разделитель!) пишете обратно через push_write сервером ...и клиент её получает, но разделителя то нет - push_read для эхо-ответа вызван не будет. Вообще, через telnet для кода сервера из последнего поста это очень хорошо видно)
PM   Вверх
shootnix
Дата 22.11.2011, 20:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 108
Регистрация: 3.9.2005
Где: Казахстан

Репутация: 2
Всего: 2



Цитата(DurRandir @ 22.11.2011,  15:50)
Вы так и не привели в одном посте код клиента и сервера) Но проблема в том, что читаете вы через push_read в line-mode что клиентом, что сервером. А этот режим отбрасывает разделитель строк, и возвращает вам строчку без него. Потом вы её (не добавляя разделитель!) пишете обратно через push_write сервером ...и клиент её получает, но разделителя то нет - push_read для эхо-ответа вызван не будет. Вообще, через telnet для кода сервера из последнего поста это очень хорошо видно)

Огромное спасибо за совет, действительно, такой момент я упустил. Исправил, все работает, еще раз спасибо! 
PM WWW ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Perl"
korob2001
sharq
  • В этом разделе обсуждаются общие вопросы по языку Perl
  • Если ваш вопрос относится к системному программированию, задавайте его здесь
  • Если ваш вопрос относится к CGI программированию, задавайте его здесь
  • Интерпретатор Perl можно скачать здесь ActiveState, O'REILLY, The source for Perl
  • Справочное руководство "Установка perl-модулей", можно скачать здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, korob2001, sharq.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Perl: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0938 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.