Perl: удаленный shell типа клиент-сервер

Тема в разделе "WASM.UNIX", создана пользователем AndreyMust19, 27 июл 2010.

  1. AndreyMust19

    AndreyMust19 New Member

    Публикаций:
    0
    Регистрация:
    20 окт 2008
    Сообщения:
    714
    Учусь программировать на Perl, поэтому решил сделать программу, способную по сети выполнять команды на другом компьютере.
    С открытием соединения и подключением клиента к серверу нет проблем. Проблемы с отправкой-получением данных. Через один полнодуплексный сокет построчно:
    - Клиент посылает команду серверу
    - Сервер возвращает результат
    Так клиент и сервер должны по очереди отправлять друг другу строки.
    Примеры и исходники из интернета не работают, везде написано одно и то же (слово в слово) и посылается только 1 команда только с 1 ответом, после чего и клиент и сервер закрывают сокет.

    Вот что в данный момент написано (часть взята из http://perldoc.perl.org/perlipc.html#Sockets:-Client/Server-Communication):

    Сервер

    Код (Text):
    1. #!/usr/bin/perl
    2.  
    3. #use strict;
    4. #BEGIN { $ENV{PATH} = '/usr/ucb:/bin' }
    5. use Socket;
    6. my $EOL = "\015\012";
    7.  
    8. $prompt = "Prompt:";
    9.  
    10. sub logmsg { print "$0 $$: @_ at ", scalar localtime, "\n" }
    11.  
    12. #$remote = shift || 'localhost';
    13. my $port = shift || 2345;
    14. my $proto = getprotobyname('tcp');
    15.  
    16. ($port) = $port =~ /^(\d+)$/ or die "invalid port";
    17.  
    18. socket(out, PF_INET, SOCK_STREAM, $proto) || die "socket: $!";
    19. setsockopt(out, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) || die "setsockopt: $!";
    20. #bind(Server, sockaddr_in($port, INADDR_ANY)) || die "bind: $!";
    21. bind(out, sockaddr_in($port, INADDR_LOOPBACK)) || die "bind: $!";
    22. listen(out,SOMAXCONN) || die "listen: $!";
    23.  
    24. logmsg "server started on port $port";
    25.  
    26. #$SIG{CHLD} = \&REAPER;
    27.  
    28. for ( ; $paddr = accept(in,out); ) {
    29.     ($port,$iaddr) = sockaddr_in($paddr);
    30.     $name = gethostbyaddr($iaddr,AF_INET);
    31.     logmsg "connection from $name [",inet_ntoa($iaddr), "]at port $port";
    32.     #print in "Hello there, $name, it's now ",scalar localtime, $EOL;
    33.     #print in $prompt,$EOL;
    34. print in '$ ';
    35. $data = <in>;
    36. #$count = sysread(in, $data, 1024);
    37. print $data;
    38. print in "HURA!\n";
    39. #    if ($data == "hello$EOF") { print "HURA!"; };
    40.  
    41. #    while (recv(out, $command, 4, 0)) {
    42. #        print 'recv';        
    43. #        print in "\$ $command";
    44. #    };
    45. }
    46. print "HURA!\n";
    47. close in;
    Клиент

    Код (Text):
    1. #!/usr/bin/perl
    2. #use strict;
    3. use Socket;
    4. #my ($remote,$port, $iaddr, $paddr, $proto, $line);
    5. my $EOL = "\015\012";
    6.  
    7. $prompt = "Prompt1:";
    8.  
    9. $remote = shift || 'localhost';
    10. $port = shift || 2345;
    11. if ($port =~ /\D/) { $port = getservbyname($port, 'tcp') }
    12. die "No port" unless $port;
    13. $iaddr = inet_aton($remote) || die "no host: $remote";
    14. $paddr = sockaddr_in($port, $iaddr);
    15. $proto = getprotobyname('tcp');
    16. socket(in, PF_INET, SOCK_STREAM, $proto) || die "socket: $!";
    17. connect(in, $paddr) || die "connect: $!";
    18.  
    19. #$pipe STDIN,in;
    20. $work_continue = 1;
    21. do {
    22.     sysread(in, $data, 3); print $data;
    23. #    print '$ ';        # выводим приглашение
    24.     #$s = <>; print in $s;    # ожидаем ввода строки и посылаем ее серверу строку
    25. send(in, "hello", 0);
    26.     @output = <in>;
    27.     print join(" ", @output);
    28. } while ($work_continue);
    29.  
    30. #die "port $port open not shell" unless (<in> == $prompt);
    31. #print STDOUT "Success\n";
    32. #while (<in>) { print;
    33. #while (<STDIN>);
    34. #};
    35.  
    36. close (in) || die "close: $!";
    37. exit;
     
  2. loginrl_103

    loginrl_103 New Member

    Публикаций:
    0
    Регистрация:
    8 фев 2008
    Сообщения:
    271
    тёплые розовые крокодилы летели по небу, ага
     
  3. AndreyMust19

    AndreyMust19 New Member

    Публикаций:
    0
    Регистрация:
    20 окт 2008
    Сообщения:
    714
    Похоже, лучше использовать:
    для чтения - sysread.
    для записи - send.
    В recv надо добавлять размер принимаемых данных, а он неизвестен.
     
  4. skomarov

    skomarov New Member

    Публикаций:
    0
    Регистрация:
    14 май 2008
    Сообщения:
    389
    AndreyMust19
    Может быть размер буфера для приема данных?
     
  5. AndreyMust19

    AndreyMust19 New Member

    Публикаций:
    0
    Регистрация:
    20 окт 2008
    Сообщения:
    714
    Получилось:

    Сервер

    Код (Text):
    1. #!/usr/bin/perl
    2.  
    3. #use strict;
    4. #BEGIN { $ENV{PATH} = '/usr/ucb:/bin' }
    5. use Socket;
    6. my $EOL = "\015\012";
    7.  
    8. $prompt = "Prompt:";
    9.  
    10. sub logmsg { print "$0 $$: @_ at ", scalar localtime, "\n" }
    11.  
    12. my $port = shift || 2345;
    13. my $proto = getprotobyname('tcp');
    14.  
    15. ($port) = $port =~ /^(\d+)$/ or die "invalid port";
    16.  
    17. socket(out, PF_INET, SOCK_STREAM, $proto) || die "socket: $!";
    18. setsockopt(out, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) || die "setsockopt: $!";
    19. #bind(Server, sockaddr_in($port, INADDR_ANY)) || die "bind: $!";
    20. bind(out, sockaddr_in($port, INADDR_LOOPBACK)) || die "bind: $!";
    21. listen(out,SOMAXCONN) || die "listen: $!";
    22.  
    23. logmsg "server started on port $port";
    24. wait_conn:
    25. print "wait connection ...\n";
    26.  
    27. if ($paddr = accept(in,out)) {
    28.     print "begin working ...\n";
    29.     if (!$work_begin) {
    30.         ($port,$iaddr) = sockaddr_in($paddr);
    31.         $name = gethostbyaddr($iaddr,AF_INET);
    32.         logmsg "connection from $name [",inet_ntoa($iaddr), "]at port $port";
    33.         $count = sysread(in, $data, 128);   # Принимаем приветствие
    34.         print "Принято ${count} байт от $name [",inet_ntoa($iaddr),"]\n";
    35.         if ($data eq 'Hello!') { print "success connection!\n"; };
    36.         send(in, "Prompt", 0);
    37.         $work_begin = 1;
    38.     };
    39. };
    40. do {
    41.     print "input:\n";
    42.     $count = sysread(in, $data, 128);   # Принимаем команды
    43.     print "Принято ${count} байт от $name [",inet_ntoa($iaddr),"]\n";
    44.     if ($data eq "exit\n") {
    45.         print "exit\n";
    46.         print "end connection ...\n";
    47.         close in;
    48.         $work_begin = 0;
    49.         goto wait_conn;
    50.     };
    51.     print "data:$data\n";
    52.     send(in, "echo", 0);
    53. } while(1);
    Клиент

    Код (Text):
    1. #!/usr/bin/perl
    2. #use strict;
    3. use Socket;
    4. my $EOL = "\015\012";
    5.  
    6. $prompt = "Prompt1:";
    7.  
    8. $remote = shift || 'localhost';
    9. $port = shift || 2345;
    10. if ($port =~ /\D/) { $port = getservbyname($port, 'tcp') }
    11. die "No port" unless $port;
    12. $iaddr = inet_aton($remote) || die "no host: $remote";
    13. $paddr = sockaddr_in($port, $iaddr);
    14. $proto = getprotobyname('tcp');
    15. socket(in, PF_INET, SOCK_STREAM, $proto) || die "socket: $!";
    16. connect(in, $paddr) || die "connect: $!";
    17.  
    18. # Отправляем приветствие
    19. send(in, "Hello!", 0);
    20.  
    21. # Принимаем данные
    22. $count = sysread(in, $data, 128);
    23. if ($data eq 'Prompt') {
    24.     $work_continue = 1;
    25.     do {
    26.         print '$ ';
    27.         $s = <>;        # вводим строку с клавиатуры
    28.         if ($s eq "exit\n") { $work_continue = 0; };
    29.         send(in, $s, 0);    # отправляем ее серверу
    30.         $count = sysread(in, $output, 128);
    31.         print "$output\n";
    32.     } while ($work_continue);
    33. };
    34. print "exit\n";
    35. close (in) || die "close: $!";
    36. exit;
     
  6. loginrl_103

    loginrl_103 New Member

    Публикаций:
    0
    Регистрация:
    8 фев 2008
    Сообщения:
    271
    открой для себя nc/bash,ssh
     
  7. AndreyMust19

    AndreyMust19 New Member

    Публикаций:
    0
    Регистрация:
    20 окт 2008
    Сообщения:
    714
    loginrl_103
     
  8. AndreyMust19

    AndreyMust19 New Member

    Публикаций:
    0
    Регистрация:
    20 окт 2008
    Сообщения:
    714
    Нужно передавать неск. строк.
    А shell работает так, что принимает данные с другой стороны пока не встретит символ '\n'.
    Как проверить что другая сторона ждет от нас данные, а не отсылает их?

    Sorry. Ошибка оказалась в другом месте. Передача неск. строк и так работает, нужно было увеличить размер приемного буфера.
     
  9. loginrl_103

    loginrl_103 New Member

    Публикаций:
    0
    Регистрация:
    8 фев 2008
    Сообщения:
    271
    на кой чёрт превращать васм в подобие говённого бложика? - а сегодня мы с вами пишем hello world!

    я как бэ предположу что эта тема интересна чуть менее чем никому >_<
     
  10. AndreyMust19

    AndreyMust19 New Member

    Публикаций:
    0
    Регистрация:
    20 окт 2008
    Сообщения:
    714
    Был вопрос я о нем. Затем вопрос разрешился, я об этом написал. Пока вопросов нет.