2010-02-04 19 views
8

Köşeli bir TCP sunucusunda çalışıyorum. Ana iş parçacığında, bir yuva dinler ve yeni gelen bağlantılar için yeni bir iş parçacığı oluşturur. Gelen tüm bağlantıları bir hashta kaydetmek istiyorum, böylece onlara başka bir iş parçacığından erişebiliyorum.Soketleri bir karta nasıl kaydederim ve onları başka bir iş parçacığından geçiririm?

Monitörün içinden yeni eklenen bağlantıları okuyamıyorum. Monitör iş parçacığı oluştururken yeni istemciler karma oluşturulduğu görünüyor.

Tüm soketlerin listesini nasıl tutarım ve bunları monitörüm iş parçacığımdan nasıl geçiririm?

Güncel kodu:

#!/usr/bin/perl 
use strict; 
use IO::Socket; 
use threads; 
use Thread::Queue; 

# init 
my $clients = {}; 
my $queue = Thread::Queue->new; 

# thread that monitors 
threads->create("monitor"); 

# create the listen socket 
my $listenSocket = IO::Socket::INET->new(LocalPort => 12345, 
             Listen => 10, 
             Proto => 'tcp', 
             Reuse => 1); 

# make sure we are bound to the port 
die "Cant't create a listening socket: [email protected]" unless $listenSocket; 

print "Server ready. Waiting for connections on 34567 ... \n"; 

# wait for connections at the accept call 
while (my $connection = $listenSocket->accept) { 
    # set client socket to non blocking 
    my $nonblocking = 1; 
    ioctl($connection, 0x8004667e, \\$nonblocking); 

    # autoflush 
    $connection->autoflush(1); 

    # debug 
    print "Accepted new connection\n"; 

    # add to list 
    $clients->{time()} = $connection; 

    # start new thread and listen on the socket 
    threads->create("readData", $connection); 
} 

sub readData { 
    # socket parameter 
    my ($client) = @_; 

    # read client 
    while (<$client>) { 
     # remove newline 
     chomp $_; 

    # add to queue 
     $queue->enqueue($_); 
    } 

    close $client; 
} 

sub monitor { 
    # endless loop 
    while (1) { 

     # loop while there is something in the queue 
     while ($queue->pending) { 

      # get data from a queue 
      my $data = $queue->dequeue; 

      # loop all sockets 
      while (my ($key, $value) = each(%$clients)) { 

       # send to socket 
       print $value "$data\n"; 

      } 
     } 

     # wait 0,25 seconds 
     select(undef, undef, undef, 0.25); 
    } 
} 

close $listenSocket; 
+0

İpucu, muhtemelen sizin için yararlı olabilir, belki de değil: Hiç 'IO :: Multiplex' adlı bir modül gördünüz mü? – fennec

cevap

8

Sen threads::shared den share aracılığıyla $clients paylaşmak gerekir:

my $clients = &share({}); 

eski moda sözdizimi nedeniyle Perl'in prototipler ile belgelenmiş bir konuya etmektir. at least Perl 5.8.9 varsa, bunun yerine daha güzel olan

my $clients = shared_clone({}); 
kullanın.

Ayrıca, bir kilitle, , ör. Son olarak

my $clients_lock : shared; 
{ 
    lock $clients_lock; 
    $clients->{time()} = fileno $connection; 
} 

, IO::Socket::INET örneği Perl typeglobs, çünkü bunları paylaşmaz, bu yüzden yerine $clients için (fileno itibaren) kendi soket tanımlayıcılar ekleyemezsiniz ardından fdopen

open my $fh, ">&=", $sockdesc or warn ... 
gerekli soket

programı aşağıdaki diğer bağlı soketlere gelen verileri tekrar:

#!/usr/bin/perl 

use strict; 
use IO::Socket; 
use threads; 
use threads::shared; 
use Thread::Queue; 

# init 
my $clients = &share({}); 
my $clients_lock : shared; 

my $queue = Thread::Queue->new; 

# thread that monitors 
threads->create("monitor"); 

# create the listen socket 
my $port = 12345; 
my $listenSocket = IO::Socket::INET->new(
    LocalPort => $port, 
    Listen  => 10, 
    Proto  => 'tcp', 
    Reuse  => 1 
); 

# make sure we are bound to the port 
die "Can't create a listening socket: [email protected]" unless $listenSocket; 

print "Server ready. Waiting for connections on $port ... \n"; 

# wait for connections at the accept call 
while (my $connection = $listenSocket->accept) { 
    # set client socket to non blocking 
    my $nonblocking = 1; 
    ioctl($connection, 0x8004667e, \\$nonblocking); 

    # autoflush 
    $connection->autoflush(1); 

    # debug 
    print "Accepted new connection\n"; 

    # add to list 
    { 
    lock $clients_lock; 
    $clients->{time()} = fileno $connection; 
    } 

    # start new thread and listen on the socket 
    threads->create("readData", $connection); 
} 

sub readData { 
    # socket parameter 
    my ($client) = @_; 

    # read client 
    while (<$client>) { 
    chomp; 
    $queue->enqueue($_); 
    } 

    close $client; 
} 

sub monitor { 
    # endless loop 
    while (1) { 
    # loop while there is something in the queue 
    while ($queue->pending) { 
     # get data from a queue 
     my $data = $queue->dequeue; 

     # loop all sockets 
     { 
     lock $clients_lock; 
     while (my ($key, $value) = each(%$clients)) { 
      # send to socket 
      if (open my $fh, ">&=", $value) { 
      print $fh "$data\n"; 
      } 
      else { 
      warn "$0: fdopen $value: $!"; 
      } 
     } 
     } 
    } 

    # wait 0,25 seconds 
    select(undef, undef, undef, 0.25); 
    } 
} 

close $listenSocket; 
+1

+1 Sadece aynı şeyleri anladım. –

+0

Teşekkür ederim! Şimdi bir çekicilik gibi çalışıyor :) – Dieterve

+0

@Dieterve Hoş Geldiniz! –

1

çok fazla deneyim Perl konuları kullanarak yok mu, ama sadece istemci listesi paylaşmak istiyorum düşünüyorum:

 
    use threads::shared ; 
    my $clients : shared = {}; 


Güncelleme:

Perl hakkında şikayet:

my $hash : shared = {}; 

ama birlikte ok gibi görünüyor: Ayrıca

my $hash = {}; 
share($hash); 

, bu kodu:

my $hash = { key1 => "value1" }; 
share($hash); 

hashtable temizlemek gibi görünüyor, ama

my $hash = {}; 
share($hash); 
$hash->{key1} = "value1"; 

beklediğim gibi çalışıyor.

+0

Bu işe yaramazsa, 2. satır hata verir "Test.pl satır 9'da paylaşılan skaler için geçersiz değer" – Dieterve

İlgili konular