Учусь программировать на Perl, поэтому решил сделать программу, способную по сети выполнять команды на другом компьютере. С открытием соединения и подключением клиента к серверу нет проблем. Проблемы с отправкой-получением данных. Через один полнодуплексный сокет построчно: - Клиент посылает команду серверу - Сервер возвращает результат Так клиент и сервер должны по очереди отправлять друг другу строки. Примеры и исходники из интернета не работают, везде написано одно и то же (слово в слово) и посылается только 1 команда только с 1 ответом, после чего и клиент и сервер закрывают сокет. Вот что в данный момент написано (часть взята из http://perldoc.perl.org/perlipc.html#Sockets:-Client/Server-Communication): Сервер Код (Text): #!/usr/bin/perl #use strict; #BEGIN { $ENV{PATH} = '/usr/ucb:/bin' } use Socket; my $EOL = "\015\012"; $prompt = "Prompt:"; sub logmsg { print "$0 $$: @_ at ", scalar localtime, "\n" } #$remote = shift || 'localhost'; my $port = shift || 2345; my $proto = getprotobyname('tcp'); ($port) = $port =~ /^(\d+)$/ or die "invalid port"; socket(out, PF_INET, SOCK_STREAM, $proto) || die "socket: $!"; setsockopt(out, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) || die "setsockopt: $!"; #bind(Server, sockaddr_in($port, INADDR_ANY)) || die "bind: $!"; bind(out, sockaddr_in($port, INADDR_LOOPBACK)) || die "bind: $!"; listen(out,SOMAXCONN) || die "listen: $!"; logmsg "server started on port $port"; #$SIG{CHLD} = \&REAPER; for ( ; $paddr = accept(in,out); ) { ($port,$iaddr) = sockaddr_in($paddr); $name = gethostbyaddr($iaddr,AF_INET); logmsg "connection from $name [",inet_ntoa($iaddr), "]at port $port"; #print in "Hello there, $name, it's now ",scalar localtime, $EOL; #print in $prompt,$EOL; print in '$ '; $data = <in>; #$count = sysread(in, $data, 1024); print $data; print in "HURA!\n"; # if ($data == "hello$EOF") { print "HURA!"; }; # while (recv(out, $command, 4, 0)) { # print 'recv'; # print in "\$ $command"; # }; } print "HURA!\n"; close in; Клиент Код (Text): #!/usr/bin/perl #use strict; use Socket; #my ($remote,$port, $iaddr, $paddr, $proto, $line); my $EOL = "\015\012"; $prompt = "Prompt1:"; $remote = shift || 'localhost'; $port = shift || 2345; if ($port =~ /\D/) { $port = getservbyname($port, 'tcp') } die "No port" unless $port; $iaddr = inet_aton($remote) || die "no host: $remote"; $paddr = sockaddr_in($port, $iaddr); $proto = getprotobyname('tcp'); socket(in, PF_INET, SOCK_STREAM, $proto) || die "socket: $!"; connect(in, $paddr) || die "connect: $!"; #$pipe STDIN,in; $work_continue = 1; do { sysread(in, $data, 3); print $data; # print '$ '; # выводим приглашение #$s = <>; print in $s; # ожидаем ввода строки и посылаем ее серверу строку send(in, "hello", 0); @output = <in>; print join(" ", @output); } while ($work_continue); #die "port $port open not shell" unless (<in> == $prompt); #print STDOUT "Success\n"; #while (<in>) { print; #while (<STDIN>); #}; close (in) || die "close: $!"; exit;
Похоже, лучше использовать: для чтения - sysread. для записи - send. В recv надо добавлять размер принимаемых данных, а он неизвестен.
Получилось: Сервер Код (Text): #!/usr/bin/perl #use strict; #BEGIN { $ENV{PATH} = '/usr/ucb:/bin' } use Socket; my $EOL = "\015\012"; $prompt = "Prompt:"; sub logmsg { print "$0 $$: @_ at ", scalar localtime, "\n" } my $port = shift || 2345; my $proto = getprotobyname('tcp'); ($port) = $port =~ /^(\d+)$/ or die "invalid port"; socket(out, PF_INET, SOCK_STREAM, $proto) || die "socket: $!"; setsockopt(out, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) || die "setsockopt: $!"; #bind(Server, sockaddr_in($port, INADDR_ANY)) || die "bind: $!"; bind(out, sockaddr_in($port, INADDR_LOOPBACK)) || die "bind: $!"; listen(out,SOMAXCONN) || die "listen: $!"; logmsg "server started on port $port"; wait_conn: print "wait connection ...\n"; if ($paddr = accept(in,out)) { print "begin working ...\n"; if (!$work_begin) { ($port,$iaddr) = sockaddr_in($paddr); $name = gethostbyaddr($iaddr,AF_INET); logmsg "connection from $name [",inet_ntoa($iaddr), "]at port $port"; $count = sysread(in, $data, 128); # Принимаем приветствие print "Принято ${count} байт от $name [",inet_ntoa($iaddr),"]\n"; if ($data eq 'Hello!') { print "success connection!\n"; }; send(in, "Prompt", 0); $work_begin = 1; }; }; do { print "input:\n"; $count = sysread(in, $data, 128); # Принимаем команды print "Принято ${count} байт от $name [",inet_ntoa($iaddr),"]\n"; if ($data eq "exit\n") { print "exit\n"; print "end connection ...\n"; close in; $work_begin = 0; goto wait_conn; }; print "data:$data\n"; send(in, "echo", 0); } while(1); Клиент Код (Text): #!/usr/bin/perl #use strict; use Socket; my $EOL = "\015\012"; $prompt = "Prompt1:"; $remote = shift || 'localhost'; $port = shift || 2345; if ($port =~ /\D/) { $port = getservbyname($port, 'tcp') } die "No port" unless $port; $iaddr = inet_aton($remote) || die "no host: $remote"; $paddr = sockaddr_in($port, $iaddr); $proto = getprotobyname('tcp'); socket(in, PF_INET, SOCK_STREAM, $proto) || die "socket: $!"; connect(in, $paddr) || die "connect: $!"; # Отправляем приветствие send(in, "Hello!", 0); # Принимаем данные $count = sysread(in, $data, 128); if ($data eq 'Prompt') { $work_continue = 1; do { print '$ '; $s = <>; # вводим строку с клавиатуры if ($s eq "exit\n") { $work_continue = 0; }; send(in, $s, 0); # отправляем ее серверу $count = sysread(in, $output, 128); print "$output\n"; } while ($work_continue); }; print "exit\n"; close (in) || die "close: $!"; exit;
Нужно передавать неск. строк. А shell работает так, что принимает данные с другой стороны пока не встретит символ '\n'. Как проверить что другая сторона ждет от нас данные, а не отсылает их? Sorry. Ошибка оказалась в другом месте. Передача неск. строк и так работает, нужно было увеличить размер приемного буфера.
на кой чёрт превращать васм в подобие говённого бложика? - а сегодня мы с вами пишем hello world! я как бэ предположу что эта тема интересна чуть менее чем никому >_<