Thread Linux Monitor: Client-Server Rollen (15 answers)
Opened by bloonix at 2006-05-25 16:52

bloonix
 2006-05-30 01:40
#38800 #38800
User since
2005-12-17
1615 Artikel
HausmeisterIn
[Homepage]
user image
[quote=ptk,29.05.2006, 21:03]Das ist ein Klassiker, was massive Verarbeitung mithilfe von select() angeht.[/quote]
Hi ptk,

ich werde die select() Methode für den Listener verwenden, aber ich denke
das das nicht reichen wird. Wie oben schon angesprochen suche ich
nach einer Möglichkeit, die eingehenden Requests weiterleiten zu können,
damit ich eine Lastenverteilung habe.

Als Lösung habe ich mir folgendes gedacht...
(alles kurze Beispiele, aber sie funktionieren)

Ich habe einen Listener, der auf eingehende Requests wartet. Der Listener
hat eine Liste von offenen Ports, die er aus einer Pipe liest.

[b]listener.pl[/b]
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
use strict;
use warnings;
use IO::Socket::INET;
use Fcntl;

my $pipe_name = './myFIFO';
my $host      = '127.0.0.1';
my $port      = 43600;
my @open_ports;

my $listener = IO::Socket::INET->new( LocalHost  => $host
                                   , LocalPort  => $port
                                   , Type       => SOCK_STREAM
                                   , Proto      => 'tcp'
                                   , Listen     => 10
                                   , Reuse      => 1
                                   ) or die "can't open socket over port $port";

while (my $client = $listener->accept()) {
  chomp (my $request = <$client>);

  # wenn @open_ports leer ist, werden die naechsten Ports
  # aus der Pipe gelesen...
  unless (@open_ports) {
     die "pipe $pipe_name is not open" unless -e $pipe_name;
     sysopen my $PIPE,$pipe_name,O_RDONLY or die $!;
     @open_ports = <$PIPE>;
     close $PIPE;
  }

  # an den Client wird der naechste freie Port gesendet und das
  # Array gleichermassen verkuertzt
  print $client shift @open_ports;
  close $client;
}

close($listener);


Nun habe ich die Serverprozesse, die ihren Port, auf den sie laufen, in die
Pipe schreiben, sobald sie zur Verfügung stehen.

[b]server.pl[/b]
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
use strict;
use warnings;
use IO::Socket::INET;
use Fcntl;

sub i_am_free {
  my $pipe = shift;
  my $port = shift;
  unless (-p $pipe) {
     require POSIX;
     POSIX::mkfifo($pipe,0600) or die $!;
  }
  sysopen my $PIPE,$pipe,O_WRONLY or die $!;
  print $PIPE "$port\n";
  close $PIPE;
}

my $pipe_name = './myFIFO';
my $host      = '127.0.0.1';
my $port      = shift @ARGV;
die "Usage: $0 <port>\n" unless $port =~ /^\d+$/ && $port > 0 && $port < 65657;

my $server = IO::Socket::INET->new( LocalHost  => $host
                                 , LocalPort  => $port
                                 , Type       => SOCK_STREAM
                                 , Proto      => 'tcp'
                                 , Listen     => 10
                                 , Reuse      => 1
                                 ) or die "can't open socket over port $host:$port";

i_am_free($pipe_name,$port);

while (my $client = $server->accept()) {
  my $request = <$client>;
  if ($request) {
     # processing the request
  }
  close $client;
  i_am_free($pipe_name,$port);
}

close($server);


Zu guter Letzt habe ich dann noch den Client, der zunächst einen
Request an den Listener schickt und einen Port von diesem erhält. Mit
dem neuen Port verbindet sich dann der Client zu einem Server.

[b]client.pl[/b]
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
use strict;
use warnings;
use IO::Socket::INET;

my $addr = '127.0.0.1';
my $port = 43600;
my $data = {};

while (1) {
  my $port_request = IO::Socket::INET->new( PeerAddr => $addr
                                          , PeerPort => $port
                                          , Proto    => 'tcp'
                                          , Type     => SOCK_STREAM
                                          ) or die "can't connect to $addr:$port";

  print $port_request "1\n";
  my $new_port = <$port_request>;
  close $port_request;
  print $new_port; # just a info for tests
  chomp $new_port;

  my $new_client = IO::Socket::INET->new( PeerAddr => $addr
                                        , PeerPort => $new_port
                                        , Proto    => "tcp"
                                        , Type     => SOCK_STREAM
                                        ) or die "can't connect to $addr:$port";

  print $new_client "1\n";
  close $new_client;
  sleep(1);
}


Zusammenfassung:

1. die Server schreiben ihren Port in eine Pipe
2. der Listener liest die Pipe aus
3. der Client startet einen Request an den Listener
4. der Listener sendet den nächsten freien Port
5. der Client startet einen Request zu einem Server

Das Ganze funktioniert bis hierhin, nur habe ich nicht die geringste
Ahnung, ob das so Gang und Gebe ist. Ich kenne mich nicht mit Client-
Server-Verbindungen aus und hoffe mir kann hier jemand noch
weiterhelfen.

Viele Grüße,
opi

Edit:
Wenn jemand Projekte oder Software kennt, wo ich solches Threading
gelebt wird oder Links kennt, wo ich mir sowas anlesen kann, dann bin ich
für alles, was ihr mir postet dankbar... ich bin absolut wissbegierig auf
dieses Thema. =)\n\n

<!--EDIT|opi|1148939690-->
What is a good module? That's hard to say.
What is good code? That's also hard to say.
One man's Thing of Beauty is another's man's Evil Hack.

View full thread Linux Monitor: Client-Server Rollen