Форкирование подпрограммы, которая открывает пару сокетов - PullRequest
0 голосов
/ 07 сентября 2018

Я хотел бы раскошелиться на подпрограмму, которая открывает сокет.

Я написал код, чтобы открыть сокет, получить данные и распечатать полученные данные. GUI написан с использованием Tk

Ниже приведен код, он выполняет в основном то, что я хочу сделать, за исключением того, что не разветвляется подпрограмма new_port. Каждый раз, когда я нажимаю кнопку submit, окно Tk застревает. Я ищу помощи по добавлению fork к подпрограмме new_port, чтобы она порождала новый дочерний процесс. У меня лично есть проблемы с выполнением fork без синтаксических ошибок или без вставки сокета в дочерний процесс.

Идея заключается в том, что я могу заполнить новый порт в форме и нажать «Отправить». Окно закрывается, затем я снова нажимаю новый, вставляю новый порт, и теперь второй сокет открыт одновременно с первым. например порты 1234 и 5678 прослушиваются одновременно.

#!/usr/bin/perl -w

use IO::Socket::INET;
use Tk;

$myip = `ifconfig | grep -i inet | head -1 | cut -d ":" -f2 | cut -d " " -f1`;

sub new_port {

    my $socket = new IO::Socket::INET(
        LocalHost => "$myip",
        LocalPort => "$myport",
        Proto     => 'tcp' Reuse => 1
   );

    die "Cannot create socket on local host" unless $socket;
    print "Server waiting for client connection on port $myport\n";

    while ( 1 ) {

        my $client_socket  = $socket->accept();
        my $client_address = $client_socket->peerhost();
        my $client_port    = $client_socket->peerport();
        my $input_data     = "";
        my $received_data  = "";

        do {
            $client_socket->recv($received_data, 65536);
            $input_data = $input_data . $received_data;
        } while ( $received_data ne "" );

        print "INPUT----------------------------------\n";
        print "Data from $client_address on port $client_port\n";
        print $input_data;
        shutdown($client_socket, 1);
    }
}

sub new_port_window {

    my $sw = MainWindow->new;

    $sw->geometry("200x100");
    $sw->title("port opener");
    $sw->Label(
        -text "Insert port #"
    )->place(
        -anchor => 'center',
        -relx => 0.5,
        -rely => 0.2
    );
    $sw->Entry(
        -bg => 'white',
        -fg => 'black',
        -textvariable => \$myport
    )->place(
        -anchor => 'center',
        -relx => 0.5,
        -rely => 0.4
    );
    $sw->Button(
        -text "submit",
        -command => sub {new_port}
    )->place(
        width   => 100,
        -anchor => "center",
        -relx   => 0.5,
        -rely   => 0.8
    );
}

my $mw = MainWindow->new;

$mw->geometry("150x100");
$mw->title("GUI TEST NEW FUNCTION");
$mw->Label(
    -text => "click new"
)->place(
    -anchor => "center",
    -relx => 0.5,
    -rely => 0.3
);
$mw->Button(
    -text => "NEW",
    -command => sub {new_port_window}
)->place(
    -width => 50,
    -anchor => "center",
    -relx => 0.5,
    -rely => 0.8
);

MainLoop;

1 Ответ

0 голосов
/ 07 сентября 2018

Прошло много времени с тех пор, как я впервые попробовал это, поэтому я забываю, так ли это должно быть, или это просто один из многих способов работы, но суть такова:

  1. создать пару сокетов перед вилкой
  2. выполнить вилку
  3. использовать один сокет в родительском, а другой в дочернем
  4. если вы хотите, чтобы сокет был однонаправленным (от родителя только для потомка или потомка для родителя), вызовите shutdown на соответствующем сокете как у родителя, так и у потомка

Поскольку вы хотите отправлять данные только от родителя к ребенку, это выглядит как

($sock_child, $sock_par) = IO::Socket->socketpair(
    Socket::AF_UNIX, Socket::SOCK_STREAM, Socket::PF_UNSPEC);
$pid = fork;
if ($pid) {
    # parent
    shutdown($sock_par, 0); # no more reading from parent
    print $sock_par $data_to_pass_to_child;
    ...
 } else {
    # child
    shutdown($sock_child, 1);  # no more writing in child
    $data_from_parent = <$sock_child>;
    ...
 }
...