Linux 如何在Perl中接受多个TCP连接?
我对Linux的Perl脚本有一个问题。它的主要目的是在3个应用程序之间充当中间人。它应该做什么: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的文本不包含空格
$UDP\u端口上等待UDP文本(无空格)
$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);
}
}
}
}
}
免责声明:我刚刚把它敲碎了。我想它非常脆弱。不要在没有太多测试和防弹的生产环境中尝试使用它。它可能会吃掉你的数据。它可能会尝试和