Странное поведение атрибута сокета в объекте Moose

#perl #sockets #moose

#perl #сокеты #moose

Вопрос:

У меня есть объект Moose, который имеет объект ввода-вывода:: Socket::INET в качестве одного из своих атрибутов:

 has socket => (
    is => 'ro',
    required => 1,
    lazy => 1,
    isa => 'IO::Socket::INET',
    builder => 'connect',
);
  

Сокет инициализируется в скрипте, который выглядит следующим образом (часть аутентификации удалена):

 sub connect {
    my $self = shift;
    my $host = 'A.B.C.D';
    my $port = N;

    my $handle = IO::Socket::INET->new(
        Proto     => "tcp",
        PeerAddr  => $host,
        PeerPort  => $port
    ) or die "can't connect to port $port on $host: $!";

    $handle->autoflush(1);

   # Connect to Server with $handle and authenticate
   # and if successful .......
    return $handle;
}
  

Однако я нахожу странное поведение при запуске следующего тестового кода:

 my $x = MyObject->new;
print $x->socket pack('I', 392);
  

Байты, полученные Сервером (A.B.C.D), полностью отличаются от тех, которые я отправил. Я проверил, что порядковый номер или порядок байтов не является проблемой. На самом деле простой скрипт, который создает сокет и записывает те же данные без использования Moose, работает идеально — данные поступают на сервер точно так, как ожидалось.

Должен ли я делать что-то большее, чем то, что я делаю, если мой атрибут Moose является постоянным объектом ввода-вывода:: Socket ::INET. Закрывается ли атрибут сокета или каким-либо иным образом манипулируется за моей спиной?

Спасибо.

Комментарии:

1. к вашему сведению, $handle->autoflush(1); это уже сделано для вас.

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

Ответ №1:

print В документации говорится, что вы должны заключить в блок что-либо более сложное, чем скалярная переменная для дескриптора файла. Вы пробовали:

 print { $x->socket } pack ('I', 392);
  

Или:

 $x->socket->print (pack ('I', 392));
  

Я получаю синтаксическую ошибку, если не ставлю фигурные скобки вокруг $x->socket .

Следующий код работает для меня. Вы уверены, что что-то не так в разделе аутентификации? Может быть, посмотреть на данные сокета с помощью wireshark?

 package Test;
use Moose;
use IO::Socket::INET;

has socket => (
    is => 'ro',
    required => 1,
    lazy => 1,
    isa => 'IO::Socket::INET',
    builder => 'connect',
);

sub connect {
        my $sock = IO::Socket::INET->new (
                Proto => "tcp",
                PeerAddr => "127.0.0.1",
                PeerPort => 2000,
        ) or die;
        $sock;
}

package main;

my $x = Test->new;
print { $x->socket } pack ('I', 392);
  

Комментарии:

1. Я сделал. Я также попробовал $ x-> socket-> syswrite(pack(‘I’, 392), 4) тоже. Никакой радости : (

2. В моем коде аутентификации действительно была ошибка. Приношу искренние извинения за трату вашего времени и благодарю вас за ваше терпение

Ответ №2:

Я не могу воспроизвести вашу проблему.

Я использовал

 use strict;
use warnings;

use IO::Socket::INET;
use Moose;

has socket => (
    is => 'ro',
    required => 1,
    lazy => 1,
    isa => 'IO::Socket::INET',
    builder => 'connect',
);

sub connect {
    my $self = shift;
    my $host = 'localhost';
    my $port = 12345;

    my $handle = IO::Socket::INET->new(
        Proto     => "tcp",
        PeerAddr  => $host,
        PeerPort  => $port
    ) or die "can't connect to port $port on $host: $!";

   # Connect to Server with $handle and authenticate
   # and if successful .......
    return $handle;
}

my $x = __PACKAGE__->new;
print { $x->socket } pack('I', 392);
  

И я получил

 $ nc -l -p 12345 | od -t x1
0000000 88 01 00 00
0000004
  

Что вы получаете? Что print вернулось?

Комментарии:

1. Запускался с nc -l 12345, и он выводит правильный результат. Но запустите nc на сервере, и он напечатает мусор.

2. @Gurunandan, То, что вы получаете что-то, означает, что вы правильно получаете сокет от объекта, и что это не имеет никакого отношения к Moose. И теперь вы говорите, что это даже отлично работает для localhost. Время искать в другом месте!

3. Правильно! Мой код аутентификации оставил на несколько байт больше, чем ожидал сервер, который был добавлен к следующему чтению. Приношу искренние извинения за трату вашего времени. Учитывая, что я открыл nc, на самом деле это не было пустой тратой времени. Спасибо!