Linux 如何在Perl中接受多个TCP连接?

Linux 如何在Perl中接受多个TCP连接?,linux,perl,multithreading,tcp,udp,Linux,Perl,Multithreading,Tcp,Udp,我对Linux的Perl脚本有一个问题。它的主要目的是在3个应用程序之间充当中间人。它应该做什么: 它应该能够在$UDP\u端口上等待UDP文本(无空格) 当它接收到UDP文本时,应该将其转发到连接的TCP客户端 问题是,在我第一次断开与TCP客户端的连接之前,我的应用程序目前一直在工作。然后我无法再连接到它,它在$UDP\u端口上接收到下一个UDP数据包后超时。所以,只要我想重新连接TCP,我就必须重新启动应用程序 所有这些都应该尽可能快(每毫秒计数一次)。发送到UDP或TCP的文本不包含空格

我对Linux的Perl脚本有一个问题。它的主要目的是在3个应用程序之间充当中间人。它应该做什么:

  • 它应该能够在
    $UDP\u端口上等待UDP文本(无空格)
  • 当它接收到UDP文本时,应该将其转发到连接的TCP客户端
  • 问题是,在我第一次断开与TCP客户端的连接之前,我的应用程序目前一直在工作。然后我无法再连接到它,它在
    $UDP\u端口
    上接收到下一个UDP数据包后超时。所以,只要我想重新连接TCP,我就必须重新启动应用程序

    所有这些都应该尽可能快(每毫秒计数一次)。发送到UDP或TCP的文本不包含空格。不需要同时支持多个TCP客户端,但这肯定是一个优势:-)

    以下是我当前的代码:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    use IO::Socket;
    use Net::hostent;
    use threads;
    use threads::shared;
    
    my $tcp_port = "10008";  # connection from TCP Client
    my $udp_port = "2099";  # connection from Announcer
    my $udp_password = ""; # password from Announcer
    my $title = "Middle Man server version 0.1";
    my $tcp_sock = IO::Socket::INET->new( Proto => 'tcp', LocalPort => $tcp_port, Listen => SOMAXCONN,Reuse => 1)|| die @!;
    my $udp_sock = new IO::Socket::INET(LocalPort => $udp_port, Proto => "udp") || die @!;
    
    my (@threads);
    
    print "[$title]\n";
    
    sub mySubTcp($)
    {
      my ($popup) = @_;
    
      print "[TCP][CLIENT CONNECTED]\n";
      while (my $answer = <$popup>)
      {
    chomp $answer;
    my ($pass, $announce) = split ' ', $answer;
    print $answer . '\n';
      }
      printf "[TCP][CLIENT DISCONNECTED]\n";
    }
    
    my $client = $tcp_sock->accept();
    $client->autoflush(1);
    
    
    my $thr = threads->new(\&mySubTcp, $client);
    
    
    while ($udp_sock->recv(my $buf, 1024))
    {
      chomp $buf;
    
      my $announce = $buf;
        print "[ANNOUNCE] $announce [START]\n";
        print $client $announce . "\n";
        print "[ANNOUNCE] $announce [END]\n";
    
    }
    
    #/usr/bin/perl
    严格使用;
    使用警告;
    使用IO::Socket;
    使用Net::hostent;
    使用线程;
    使用线程::共享;
    我的$tcp_port=“10008”#来自TCP客户端的连接
    我的$udp_port=“2099”#广播员连线
    我的$udp_密码=“#”播音员的密码
    my$title=“中间人服务器版本0.1”;
    我的$tcp_sock=IO::Socket::INET->new(Proto=>'tcp',LocalPort=>$tcp_port,Listen=>SOMAXCONN,重用=>1)| | die@!;
    我的$udp_sock=new IO::Socket::INET(LocalPort=>$udp_port,Proto=>“udp”)| | die@!;
    我的(@线程);
    打印“[$title]\n”;
    子mySubTcp($)
    {
    我的($popup)=@;
    打印“[TCP][客户端已连接]\n”;
    而(我的$answer=)
    {
    咀嚼$answer;
    我的($pass,$annound)=拆分“”,$answer;
    打印$answer。“\n”;
    }
    printf“[TCP][客户端已断开连接]\n”;
    }
    我的$client=$tcp_sock->accept();
    $client->autoflush(1);
    my$thr=threads->new(\&mySubTcp$client);
    而($udp_sock->recv(my$buf,1024))
    {
    咀嚼$buf;
    my$announce=$buf;
    打印“[ANNOUNCE]$ANNOUNCE[START]\n”;
    打印$client$annound。“\n”;
    打印“[annound]$annound[END]\n”;
    }
    
    下面是我在几条建议之后尝试的代码,建议不要使用线程。问题是,我甚至可以连接到TCP客户端消息“尝试设置UDP\n从未显示。可能是我做错了。TCP客户端只是连接并等待服务器发送一些数据。UDP到达,但未被接受。代码如下:

    #!/usr/bin/perl
    use strict;
    use warnings;
    use IO::Socket;
    use Net::hostent;
    use threads;
    use threads::shared;
    
    my $tcp_port = "10008";  # connection from Tcp
    my $udp_port = "2099";  # connection from Announcer
    
    my $title = "Middle Man server version 0.2";
    my $tcp_sock = IO::Socket::INET->new( Proto => 'tcp', LocalPort => $tcp_port, Listen => SOMAXCONN,Reuse => 1)|| die @!;
    
    my (@threads);
    
    print "[$title]\n";
    
    for (;;)
    {
        my $open_socket = $tcp_sock->accept();
        print "[TCP][CLIENT CONNECTED]\n";
        while (my $input = <$open_socket>)
        {
        print "Trying to setup UDP\n";
        my $udp_sock = new IO::Socket::INET(LocalPort => $udp_port, Proto => "udp") || die @!;
        while ($udp_sock->recv(my $buf, 1024)) {
              chomp $buf;
              print "\[ANNOUNCER\] $buf \[START\]\n";
              print $open_socket $buf . "\n";
              print "\[ANNOUNCER\] $buf \[END\]\n";
        }
        print "Closing UDP\n";
        close $udp_sock;
        #chomp $input;
        #print $input;
    }
    
        close $open_socket;
        printf "[TCP][CLIENT DISCONNECTED]\n";
    }
    
    !/usr/bin/perl
    严格使用;
    使用警告;
    使用IO::Socket;
    使用Net::hostent;
    使用线程;
    使用线程::共享;
    我的$tcp_port=“10008”#来自tcp的连接
    我的$udp_port=“2099”#来自播音员的连接
    my$title=“中间人服务器版本0.2”;
    我的$tcp_sock=IO::Socket::INET->new(Proto=>'tcp',LocalPort=>$tcp_port,Listen=>SOMAXCONN,重用=>1)| | die@!;
    我的(@线程);
    打印“[$title]\n”;
    对于(;;)
    {
    我的$open_socket=$tcp_sock->accept();
    打印“[TCP][客户端已连接]\n”;
    while(my$input=)
    {
    打印“正在尝试设置UDP\n”;
    我的$udp_sock=new IO::Socket::INET(LocalPort=>$udp_port,Proto=>“udp”)| | die@!;
    而($udp_sock->recv(my$buf,1024)){
    咀嚼$buf;
    打印“\[播音员\]$buf\[开始\]\n”;
    打印$open\u socket$buf。“\n”;
    打印“\[播音员\]$buf\[结束\]\n”;
    }
    打印“正在关闭UDP\n”;
    关闭$udp_sock;
    #chomp$输入;
    #打印$input;
    }
    关闭$open_插座;
    printf“[TCP][客户端已断开连接]\n”;
    }
    
    在它断开连接后,您可能希望循环并等待与
    ->再次接受的新连接

    使用strict;
    使用warnings;
    来找出任何错误也是个好主意


    编辑:我不认为glob能做你认为它能做的任何事情。

    试着把你的代码简化成最简单的程序,接受TCP连接,断开连接,然后再接受另一个。当你做到这一点时,其他的一切都只是细化细节

    Anonymous的提示非常有用。你在问题中包含的代码中有太多的小错误,所以你最好从一个简单的案例开始,然后构建它

    一个简单的TCP侦听器可能看起来像这样——它只是侦听本地主机上的一个端口并打印它所看到的内容:

    use strict; use warnings;
    use IO::Socket;
    my $socket = IO::Socket::INET->new(
        LocalHost => 'localhost',
        LocalPort => '5555',
        Proto => 'tcp',
        Listen => 1,
        Reuse => 1,
    ) or die "Could not create socket: $!";
    
    for (;;)
    {
        my $open_socket = $socket->accept();
        print "Got a connection!\n";
        while (my $input = <$open_socket>)
        {
            print $input;
        }
        close $open_socket;
        print "Connection closed.\n\n";
    }
    
    使用严格;使用警告;
    使用IO::Socket;
    my$socket=IO::socket::INET->new(
    LocalHost=>“LocalHost”,
    LocalPort=>“5555”,
    Proto=>“tcp”,
    听着=>1,
    重用=>1,
    )“或死亡”无法创建套接字:$!";
    对于(;;)
    {
    我的$open_socket=$socket->accept();
    打印“已连接!\n”;
    while(my$input=)
    {
    打印$input;
    }
    关闭$open_插座;
    打印“连接已关闭。\n\n”;
    }
    
    您需要面对一些设计问题(实际上与Perl或线程无关)

    据我所知,您的应用程序应该接收一些UDP消息,并将它们传递到通过TCP套接字连接的一个或多个客户端

    当TCP套接字上没有连接客户端时,您如何处理接收到的UDP消息?您是保存这些消息以传递给第一个连接的TCP客户端,还是放弃它们

    如果设计很简单,也就是说,如果它是沿着以下路线的东西:

    • 您的应用程序在任何给定时间最多为一个TCP客户端提供服务
    • 您的应用程序等待客户端连接到TCP套接字
    • 连接到达后,创建一个新的UDP套接字
    • 每次在UDP套接字上接收到消息时,都要通过TCP套接字发送它
    • 一旦TCP客户端断开连接,请拆下UDP套接字,返回等待TCP连接

    您根本不需要任何多线程。

    它不是线程化的,但我认为这正是您想要的:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use IO::Socket;
    use IO::Select;
    
    my $tcp_port = "10008"; 
    my $udp_port = "2099";
    
    my $tcp_socket = IO::Socket::INET->new(
                                           Listen    => SOMAXCONN,
                                           LocalAddr => 'localhost',
                                           LocalPort => $tcp_port,
                                           Proto     => 'tcp',
                                           ReuseAddr => 1,
                                          );
    
    my $udp_socket = IO::Socket::INET->new(
                                           LocalAddr => 'localhost',
                                           LocalPort => $udp_port,
                                           Proto     => 'udp',
                                          );
    
    my $read_select  = IO::Select->new();
    my $write_select = IO::Select->new();
    
    $read_select->add($tcp_socket);
    $read_select->add($udp_socket);
    
    ## Loop forever, reading data from the UDP socket and writing it to the
    ## TCP socket(s).  Might want to install some kind of signal handler to
    ## ensure a clean shutdown.
    while (1) {
    
        ## No timeout specified (see docs for IO::Select).  This will block until a TCP
        ## client connects or we have data.
        my @read = $read_select->can_read();   
    
        foreach my $read (@read) {
    
            if ($read == $tcp_socket) {
    
                ## Handle connect from TCP client.  Note that UDP connections are 
                ## stateless (no accept necessary)...
                my $new_tcp = $read->accept();
                $write_select->add($new_tcp);
    
            }
            elsif ($read == $udp_socket) {
    
                ## Handle data received from UDP socket...
                my $recv_buffer;
    
                $udp_socket->recv($recv_buffer, 1024, undef);
    
                ## Write the data read from UDP out to the TCP client(s).  Again, no 
                ## timeout.  This will block until a TCP socket is writable.  What 
                ## happens if no TCP clients are connected?  Will IO::Select throw some
                ## kind of error trying to select on an empty set of sockets, or will the
                ## data read from UDP just get dropped on the floor?  
                my @write = $write_select->can_write(); 
    
                foreach my $write (@write) {
    
                    ## Make sure the socket is still connected before writing.  Do we also
                    ## need a SIGPIPE handler somewhere?
                    if ($write->connected()) {
                        $write->send($recv_buffer);
                    }
                    else {
                        $write_select->remove($write);
                    }
    
                }
    
            }
    
        }
    
    }
    
    免责声明:我刚刚把它敲碎了。我想它非常脆弱。不要在没有太多测试和防弹的生产环境中尝试使用它。它可能会吃掉你的数据。它可能会尝试和