У меня есть проблема со сценарием Perl для Linux. Это - основная цель, должен быть посредник между 3 приложениями. Что это должно сделать:
$udp_port
Проблемой является мое приложение, в настоящее время работает до первого раза я разъединяюсь с клиентом TCP. Затем я не могу соединиться с ним больше, и это испытывает таймаут после того, как это получает следующий пакет UDP на $udp_port
. Так в основном каждый раз, когда я хочу снова соединиться с 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";
}
Вот код, я пытался после нескольких предложений обойтись без помощи поточной обработки. Проблема - даже Вы, я могу соединиться с сообщением клиента 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
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);
}
}
}
}
}
Отказ от ответственности: Я просто ударил это. Я представляю, это очень хрупкий. Не пытайтесь использовать это в производственной среде без особого тестирования и хранилища. Это может съесть ваши данные. Это может попытаться съесть свой обед. Используйте на свой риск. Нет гарантии.
Разница в семантике между временем выполнения и времени компиляции. Во втором примере код компилирует код if-else в Bytecode, и Eclipse достаточно просто уют, чтобы сказать вам, что остальная часть никогда не будет достигнута во время выполнения. Eclipse только предупреждает вас, потому что это все еще юридический код.
В вашем первом примере это ошибка, потому что код незаконно, по определению Java. Компилятор не позволяет вам создавать код байта с недоступными операторами.
-121--1020441- После того, как оно отключается, вы, вероятно, захотите циркулировать и ждать нового соединения с -> снова принять
.
Было бы также хорошей идеей использование строгое;
и используют предупреждения;
для выполнения любых ошибок.
Редактировать: И я не думаю GLOC
делает все, что вы думаете, что это там.
Попробуйте сварить ваш код в максимально простую программу, которая принимает TCP-соединение, отключает, а затем принимает другое. Когда вы зашли так далеко, все остальное просто уточняет детали.
Анонимные намёки были подсказками. В коде, который вы включили в свой вопрос, слишком много мелких ошибок, так что лучше начать всё сначала с простого кейса, а затем собрать его.
Простой 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";
}
На CPAN много контуров событий. Посмотрите на AnyEvent - после того, как вы научитесь думать о «Программе события», то он будет относительно простым (и более гибким, чем просто не блокирующий слушатель).
У вас есть некоторые проблемы с дизайном, вам нужно противостоять (которые не имеют ничего общего с Perl или Threads, действительно).
Как я понимаю, ваше приложение должно принять несколько сообщений UDP и передавать их на клиента или клиенты, подключенные к разъему TCP.
Что вы делаете с сообщениями UDP, полученные, когда клиента не подключен к розетке TCP? Вы сохраняете их, чтобы доставить на первый клиент TCP, который соединяет или просто отказаться от них?
Если дизайн прост, то есть, если это что-то вдоль линий:
Вам вообще не нуждается в многопотеке.