Schrift
[thread]12365[/thread]

IO::Socket Server, der mehrere Clients simultan "bedient"

Leser: 3


<< >> 4 Einträge, 1 Seite
FoolAck
 2008-08-17 16:39
#113601 #113601
User since
2008-05-02
69 Artikel
BenutzerIn
[default_avatar]
Ja also die Idee ist quasi sowas wie einen Chat mit IO::Socket zu machen. Allerdings kann sich ja immer nur ein Client auf den Server-Socket verbinden. Wie könnte man beliebig viele Clients ermöglichen und das ganze ohne blockende Stellen realisieren?
IO::Event und IO::Select klingen teilweise ganz interessant, aber ich komm grade nicht damit weiter....
Es wäre auch nett, wenn mir einer kurz sagen könnte, was denn bitte $socket->blocking(0) macht. Was blockt dann nicht mehr?

Threads will ich nicht benutzen und fork() fällt auch weg, weil ich alle von den Clients zum Server geschickten Daten in eine Datenstruktur packen möchte.

In Worten: Der Server soll alle Daten von allen Clients für alle anderen Clients sichtbar machen. (Halt wie im chat auch.)
Sprich clientA und clientB verbinden sich zum Server. clientA schreibt "foo". Jetzt soll der Server clientB (und allen anderen clients) diese Nachricht schicken.

Gibts da irgendeine "offensichtliche" Lösung, die mir noch nicht klar geworden ist?
Oder ist das nur mit threads möglich?

//Edit: grade das hier gefunden. Werde es mal studieren...
//Edit2: Hm, irgendwie ist das recht buggy und etwas unsauber gecodet. (Kein strict....) Ich habe ne strict Version versucht, aber da noch nichtmal bei der "nicht-strict" Version das broadcasten ordentlich funktioniert (teiweise zumindest), weiß ich nicht, ob ich mir das jetzt unbedingt antun will... Ich bin immernoch für Vorschläge offen.
//Edit3: Oha, völlig falsches Forum :X
Man verschiebe mich ins Netzwerk-Ghetto.
Und laut diesem Thread hier sollte es wohl irgendwie mit IO::Select möglich sein. Hm.
betterworld
 2008-08-17 19:30
#113612 #113612
User since
2003-08-21
2614 Artikel
ModeratorIn

user image
FoolAck+2008-08-17 14:39:31--
Allerdings kann sich ja immer nur ein Client auf den Server-Socket verbinden.


Warum das?

Das Vorgehen ist doch (bei TCP) üblicherweise so: Der Server hat ein Socket, auf dem er immer accept() macht. Wenn dann eine Verbindung reinkommt, gibt accept() ein weiteres Socket zurück, über das man mit dem Client sprechen kann. Von diesen Sockets kann der Server theoretisch beliebig viele haben.

IO::Select ist schon mal eine gute Grundlage, um so etwas zu bauen.

Es gibt auf dem CPAN noch verschiedene Module, die im Namen "Server" und/oder "Multiplexed" oder ähnlich enthalten... einfach mal angucken, ich hab die selbst noch nicht benutzt.
FoolAck
 2008-08-17 20:19
#113618 #113618
User since
2008-05-02
69 Artikel
BenutzerIn
[default_avatar]
Joar. Also inzwischen bin ich soweit:
Code (perl): (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
use strict;
use warnings;

use IO::Socket;
use IO::Select;

my $server = IO::Socket::INET->new(
    Proto     => 'tcp',
    LocalPort => shift || 1234,
    Listen    => 5,
    Timeout   => 3 * 60,
    Reuse     => 1,
);

die "server\n$!\n" if not defined $server;

my $selector = IO::Select->new($server);

my $data;
my $curr;

while (1) {
    for my $sock ($selector->can_read()) {
        if ($sock == $server) {
            my $client = $server->accept();
            $selector->add($client);
            $data = "New client (ip: ".$client->peerhost().") joined\n";
            $curr = 0;
        }
        else {
            $data = <$sock>;
            $curr = $sock;
        }

        for my $sock ($selector->can_write()) {
            next if (($sock == $server) || ($sock == $curr));
            print $sock $data;
        }
    }
}


Funktioniert eigentlich auch schon, aber ich bekomme ab und zu puren warnings-Spam mit der Warnung "Use of uninitialized value in print at sv_test.pl line 38, <GEN1> line 1.". (Hab noch nicht herausgefunden, bei was genau das passiert. Das "GEN1" wird auch manchmal zu "GEN2" bis zu "GEN4" (wahrscheinlich je nachdem wie viele clients connected sind).) Also natürlich in Bezug auf die "print $sock $data" Zeile.
Aber eigentlich sollte $data doch immer einen Wert haben, oder?

//Edit: k, die "uninitialized value" Warnungen kamen daher, dass ich die netcat sessions einfach per ctrl+c beendet habe und dadurch die Handles nicht ordnungsgemäß geschlossen wurden.
betterworld
 2008-08-17 20:45
#113621 #113621
User since
2003-08-21
2614 Artikel
ModeratorIn

user image
Wenn die Verbindung zu einem Client beendet wird, kriegst Du das Handle noch einmal von select() geliefert, damit Du die Verbindung serverseitig vernuenftig vergessen kannst.

Das heißt, bei $data = <$sock>; solltest Du prüfen, ob $data defined ist. Wenn nicht, ist entweder ein Lesefehler aufgetreten ($! ist gesetzt) oder EOF erreicht ($! ist nicht gesetzt).

Du musst übrigens aufpassen denn <$sock> blockt, bis eine ganze Zeile da ist, das ist nicht so gut im Singlethread-Server. Also lieber syswrite und so'n Kram benutzen, das hat auch gleich einen vernünftigen Check auf EOF.

Ferner solltest Du auch die Ausgabe puffern... Zurzeit schickst Du ja nur an die Clients, an die Du was schicken kannst. Besser wäre es, für die restlichen Clients die Ausgabe zu puffern, bis sie in can_write sind. Jedenfalls für einen Chat wäre das besser.

Außerdem kann auch can_write blocken.
<< >> 4 Einträge, 1 Seite



View all threads created 2008-08-17 16:39.