Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > помгите найти проблему в udp IO:Socket


Автор: gers 20.1.2008, 03:03
Здравствуйте Уважаемые коллеги!
вот есть код сервер-клиента:

Код

#!/usr/bin/perl -w

# udpqotd - сервер сообщений UDP
use strict;
use IO::Socket;

my($sock, $oldmsg, $newmsg, $hisaddr, $hishost, $MAXLEN, $PORTNO, $call, $ipaddr );
$MAXLEN = 1024;
$PORTNO = 1234;
#$LAddr = inet_aton("192.168.2.1");
$sock = IO::Socket::INET->new(LocalAddr => '192.168.2.1', LocalPort => $PORTNO, Proto => 'udp') or die "socket: $@";
$call= IO::Socket::INET->new(PeerPort=>$PORTNO, Proto=>'udp', PeerAddr =>$hishost ) or die "socket: $@";

  print "Awaiting UDP messages on port $PORTNO\n";
  $oldmsg = "This is the starting message.";
  while ($sock->recv($newmsg, $MAXLEN)) {
    my($port, $ipaddr) = sockaddr_in($sock->peername);
      $hishost = gethostbyaddr($ipaddr, AF_INET);
      
        print "Client $hishost said  ''$newmsg''\n";
      $call->send($newmsg);
        #$oldmsg = "[192.168.2.3] $newmsg";
        }
        die "recv: $!";

написал второй такойже клиент-сервер на delphi, и проблема в чем:
этот сервер должен ответить в клиентскую прогу на delphi только вываливается после того как не может определить адрес для обратного ответа:
Код

Awaiting UDP messages on port 1234
Use of uninitialized value in concatenation (.) or string at ./udp.pl line 20.
Client  said  ''test''
send: Cannot determine peer address at ./udp.pl line 21


при явной подстановке айпи: 
Код

$call= IO::Socket::INET->new(PeerPort=>$PORTNO, Proto=>'udp', PeerAddr =>'192168.2.3' ) or die "socket: $@";

все работает. в чем может быть дело?

Автор: nitr 20.1.2008, 03:17
На сколько вижу, вы удалили некоторые строки из своего скрипта. Можете показать код, так чтобы оно соответствовал тому что в вашем "редакторе". Поясню, указана ошибка в строке 19 и 20, из приведенного  - не понятно.
Может вы тестируете на одном ПК, и просто порт занят? Если я прав, то немного измените ваш скрипт, а так получается, что скрипт "не может понять клиент или сервер". Могу ошибаться, но похоже на это.

Ещё для теста можете вывести ваша переменная $hisaddr, чтобы определить, определяется она или нет.

P.S.: поправьте тему, у вас орфогр. ошибка.

Автор: gers 20.1.2008, 03:52
Простите исправил в исходное состояние, а название темы чтото не понял как менять  smile

стоят они на разных машинах, проблем с портами быть неможет, дело в том что даже вывод переменной $hishost  остается пустой, а в ней должен быть по идее адрес удаленного хоста, правильно?

нашел еще одну ошибку в 20 строке, это я ее сделал в ходе экспериментов, сейчас исправил:
Код

#!/usr/bin/perl -w

# udpqotd - сервер сообщений UDP
use strict;
use IO::Socket;

my($sock, $oldmsg, $newmsg, $hisaddr, $hishost, $MAXLEN, $PORTNO, $call, $ipaddr );
$MAXLEN = 1024;
$PORTNO = 1234;
#$LAddr = inet_aton("192.168.2.1");
$sock = IO::Socket::INET->new(LocalAddr => '192.168.2.1', LocalPort => $PORTNO, Proto => 'udp') or die "socket: $@";
$call= IO::Socket::INET->new(PeerPort=>$PORTNO, Proto=>'udp', PeerAddr =>$hishost ) or die "socket: $@";

  print "Awaiting UDP messages on port $PORTNO\n";
  $oldmsg = "This is the starting message.";
  while ($sock->recv($newmsg, $MAXLEN)) {
    my($port, $ipaddr) = sockaddr_in($sock->peername);
      $hishost = gethostbyaddr($ipaddr, AF_INET);
      
        print "Client $hishost said $newmsg\n";
      $call->send($newmsg);
        #$oldmsg = "[192.168.2.3] $newmsg";
        }
        die "recv: $!";

и ошибка при отправке обратно:
Код

send: Cannot determine peer address at ./udp.pl line 21

Автор: nitr 20.1.2008, 04:04
Я увидел, что у вас не определяется ИП smile
Цитата
Client  said  ''test''
, а должно быть примерно Client 192.168.2.3 said  ''test'', значит переменная $hishost (выше я ошибся в названии переменной, но имел эту ввиду, а не $hisaddr) не определяется! Ищите в этом ошибку.

Честно, я даже не вижу откуда вы получаете переменую $hishost.

P.S.: gers, при редактировании сообщения должна быть доступна графа с названием темы, которую и можно отредактировать.

Добавлено через 24 секунды
12-ая строка.

Добавлено через 1 минуту и 38 секунд
Не обращайте внимания, на 18-ую smile

Автор: KSURi 20.1.2008, 04:41
Код

  while ($sock->recv($newmsg, $MAXLEN)) {
    my($port, $ipaddr) = sockaddr_in($sock->peername);
      $hishost = gethostbyaddr($ipaddr, AF_INET);

Зачем во время цикла каждый раз получать данные, которые не изменяются?
Манипуляции с sockaddr_in и gethostbyaddr можно заменить вызовом одного метода peerhost.
В итоге я сделал бы так:
Код

...
$hishost = $sock->peerhost;
while($sock->recv($newnsg, $MAXLEN)) {
...


Ну и собственно по поводу ошибки:
как уже написал nitr, вы используете неинициализированную переменную $hishost в качестве адреса для подключения.
Однако, не понятно, почему это обнаруживается только при попытке посылки данных, хотя по идее должна была отработать проверка or die "socket: $@"...

Автор: gers 20.1.2008, 14:25
Спасибо за помощь! но проблема основная осталась, $hishost начала определяться, но в PeerAddr =>$hishost  она толи не доходит толи я торможу, при явной подстановке PeerAddr => '192.168.2.3' все работает. И подскажите где можно почитать про неинициализированные переменные если это с связано с моей проблемой.

Код

#!/usr/bin/perl -w

# udpqotd - сервер сообщений UDP
use strict;
use IO::Socket;

my($sock, $oldmsg, $newmsg, $hisaddr, $hishost, $MAXLEN, $PORTNO, $call, $ipaddr );
$MAXLEN = 1024;
$PORTNO = 1234;
$sock = IO::Socket::INET->new(LocalAddr => '192.168.2.1', LocalPort => $PORTNO, Proto => 'udp') or die "socket: $@";
$call= IO::Socket::INET->new(PeerPort=>$PORTNO, Proto=>'udp', PeerAddr =>$hishost ) or die "socket: $@";

  print "Awaiting UDP messages on port $PORTNO\n";
  $oldmsg = "This is the starting message.";
  while ($sock->recv($newmsg, $MAXLEN)) {
  $hishost = $sock->peerhost;
    print "Client $hishost said  $newmsg\n";
    $call->send($newmsg);
        print "$hishost\n";
        }
        die "recv: $!";

ответ:
Код

Awaiting UDP messages on port 1234
Client 192.168.2.3 said  sdf
send: Cannot determine peer address at ./udp.pl line 18

Автор: KSURi 20.1.2008, 14:59
gers, уважаемый, вы кажется совсем не поняли, что я и nitr имели ввиду.
Цитата(gers @  20.1.2008,  14:25 Найти цитируемый пост)
но проблема основная осталась, $hishost начала определяться, но в PeerAddr =>$hishost  она толи не доходит толи я торможу

Что вы такое пишете? Где она начала определяться? Давайте посмотрим последний код внимательно:
Цитата(gers @  20.1.2008,  14:25 Найти цитируемый пост)
Код

my($sock, $oldmsg, $newmsg, $hisaddr, $hishost, $MAXLEN, $PORTNO, $call, $ipaddr ); # Объявлена переменная $hishost. Инициализации нет.
$MAXLEN = 1024; # Инициализируется переменная $MAXLEN
$PORTNO = 1234; # Инициализируется переменная $PORTNO
$sock = IO::Socket::INET->new(LocalAddr => '192.168.2.1', LocalPort => $PORTNO, Proto => 'udp') or die "socket: $@"; # используется инициализированная переменная $PORTNO
$call= IO::Socket::INET->new(PeerPort=>$PORTNO, Proto=>'udp', PeerAddr =>$hishost ) or die "socket: $@"; # А вот здесь вы используете переменную $hishost, но вы ее не инициализировали! Только объявили

Код my $hishost; только объявляет переменную, но не задает ей значение, т.е. грубо говоря, в таблице символов Perl появляется упоминание о $hishost, но сама переменная пуста. Ей надо явно задать значение:
Код

$hishost = '192.168.2.3';

А потом уже подставлять в кач-ве параметра PeerAddr в создании сокета.

Добавлено через 3 минуты и 23 секунды
Цитата(gers @  20.1.2008,  14:25 Найти цитируемый пост)
$hishost = $sock->peerhost;

Метод изменили, а за цикл не вынесли)

Автор: gers 20.1.2008, 15:24
так дело в том что $hishost = 'удаленный_ip';  меняется в зависимости от адреса запроса, простите что не ясно выразился.
По идее $hishost = $sock->peerhost; должен быть в цикле иначе адрес удаленного хоста не будет менять или я неправ тут?

и так и не разобрался как поправить тему  smile 
само поле темы неизменяемое...

Автор: KSURi 20.1.2008, 18:14
Цитата(gers @  20.1.2008,  15:24 Найти цитируемый пост)
так дело в том что $hishost = 'удаленный_ip';  меняется в зависимости от адреса запроса, простите что не ясно выразился.
По идее $hishost = $sock->peerhost; должен быть в цикле иначе адрес удаленного хоста не будет менять или я неправ тут?

Вы что-то совсем непонятное написали =(
В зависимости от какого запроса будет меняться адрес? Где вообще в коде какие-то запросы?

Автор: KSURi 20.1.2008, 18:38
Так, виноват, извиняюсь.
Про peerhost я погорячился: забыл, что имею дело с UDP. Оставьте как есть (я имею ввиду про вынесение за цикл).
Однако, с $hishost все остается в силе: вы используете неинициализрованную переменную в кач-ве адреса для подключения (параметр PeerAddr на строке 11) и не понятно от каких "запросов" она будет зависить.

P.S.: почистил предыдущий пост

Автор: gers 20.1.2008, 19:06
блин вобщем подразобрался немного, все верно.
$hishost = $sock->peerhost;
$hishost переменная (айпи) возникает когда удаленный клиент посылает сообщение и происходит цикл: узнаем адрес удаленного клиента и посылаем ему ответное сообщение
а проблема в том что PeerAddr =>$hishost должен выглядеть так PeerAddr =>'$hishost'
только непойму как надо в этом случае экранировать переменную внутри ковычек? или переменную желательно заключить в ковычки еще раньше?

Автор: nitr 20.1.2008, 19:35
Цитата(gers @  20.1.2008,  19:06 Найти цитируемый пост)
а проблема в том что PeerAddr =>$hishost должен выглядеть так PeerAddr =>'$hishost'

Чушь это.

Я не знаю чего вы хотите получить, но у вас "слишком простое приложение", чтобы назвать его более менее полноценным сервером-клиетом.

udp.pl
Код
#!/usr/bin/perl
use strict;
use warnings;

use IO::Socket;

my ($sock, $oldmsg, $newmsg, $hisaddr, $hishost, $MAXLEN, $PORTNO, $ipaddr );
$MAXLEN = 1024;
$PORTNO = 1234;

$sock = IO::Socket::INET->new(LocalAddr => '192.168.2.1', LocalPort => $PORTNO, Proto => 'udp') or die "socket: $@";

print "Awaiting UDP messages on port $PORTNO\n";
$oldmsg = "This is the starting message.";
while ($sock->recv($newmsg, $MAXLEN)) {
    my($port, $ipaddr) = sockaddr_in($sock->peername);
    my $call= IO::Socket::INET->new(PeerAddr => inet_ntoa($ipaddr), PeerPort => $PORTNO, Proto=> 'udp' ) or die "socket: $@";
    
    $hishost = gethostbyaddr($ipaddr, AF_INET);
    print "Client $hishost said $newmsg\n";
    $call->send($newmsg);
}

die "recv: $!";


client.pl
Код
#!/usr/bin/perl
use strict;
use warnings;

use IO::Socket;

my $call= IO::Socket::INET->new(PeerPort=> '1234', Proto=>'udp', PeerAddr => '192.168.2.1' ) or die "socket: $@";
print $call "Test\n";


Но верно ли это всё?

Автор: gers 20.1.2008, 22:53
Большое спасибо за помощь ребята, я немного не стого начал... 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)