Socketüberwachung mit vielen Clients

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
thewulf00
User
Beiträge: 11
Registriert: Donnerstag 2. November 2006, 17:39

Hallo,

ich habe folgendes Problem und brauche mal einen Tipp, in welcher Richtung ich weitersuchen kann.
Ich habe einen Server mit einem Serversocket. Bei jedem Accept, d.h. bei einer Neuverbindung durch einen Client, möchte ich den Clientsocket auf eingehende Daten überwachen lassen, aber im Hintergrund.
Das ist normalerweise einfach: Einfach einen Thread starten, der im blocking mode clientsocket.recv() abfragt. Aber das geht bei mir leider nicht, da ich sehr viele Clientverbindungen erwarten und soviele Threads kann ich nicht starten (getestet habe ich zuhause ein Maximum von knapp über 300 und auf dem Server von knapp über 10k).

Welche Möglichkeiten habe ich jetzt, eine Socketüberwachung zu realisieren? Es sollte ungefähr so aussehen:

Wenn ein Socket aus SocketArray Daten hat:
data = Socket.recv()...
gobalesDatenArray.append(data)

Jemand irgendwelche Ideen?

Ich habe schon Select.select versucht, aber da bekomme ich zwei Probleme:
a) Select.select wartet auf ein Event aus einer übergebenen Socketliste. Was soll ich machen, wenn sich ein neuer Socket verbindet, während ich im select warte?
b) Wenn Select.select einen Socket zurückgibt, der Daten hat, dann will ich diesen Socket an einen neuen (Worker)Thread übergeben (von denen es maximal 100 gibt) und dann wieder per Select warten. Aber da der Socket noch nicht ausgelesen sein wird, bevor Select wieder wartet, gibt mir Select SOFORT den selben Socket wieder zurück. :(

Alternativ habe ich mir gedacht, ich könnte eine Schleife machen, die dauernd alle Sockets der Liste durchgeht, und im nonBlocking mode einfach socekt.recv durchführt. Wenn es keine Daten gibt, dann weiter. Dann würde aber die Prozesslast enorm steigen, nur durch so ein "billiges" Dauerüberwachen.

Dann habe ich noch Asyncore gesehen. Aber da kann man nur Eventhandler für Socketobjekte hinterlegen. Das würde mir im Zweifelsfall auch 10k oder mehr Threads gleichzeitig starten.

Hoffentlich habt ihr eine Idee!
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

select.select funktioniert doch, ich hab mal nen kleinen Chat geschriben:

Code: Alles auswählen

import socket 
import select

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
server.bind(("", 50000)) 
server.listen(1)

try: 
    while True: 
        lesen, schreiben, oob = select.select([server] + clients, [], [])

        for sock in lesen: 
            if sock is server: 
                client, addr = server.accept() 
                clients.append(client)
                print "+++ Client %s verbunden" % addr[0]
            else:
                irgendwas = sock.recv(1024)
                globalesArray.append(irgendwas)
finally:
    for c in clients: 
        c.close() 
    server.close() 
Ungetestet! mein Chat funktioniert zwar, allerdings ist das nur 'rauskopiert'

mfg
the more they change the more they stay the same
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

asyncore und asynchat machen das Arbeiten mit nicht-blockierendem IO noch einfacher. Aber ich empfehle mal einen Blick auf tornadoweb oder dieselweb, das sind zwei in Python geschriebene Webserver, die asynchrones, nicht-blockierendes IO beherrschen.

Stefan
thewulf00
User
Beiträge: 11
Registriert: Donnerstag 2. November 2006, 17:39

@dav1d: Der Trick, den ServerSocket mit in die Liste zu legen, gefällt mir gut. So werde ich das machen, vielen Dank.

@sma: Asyncore geht leider nicht, weil Asyncore ohne Kontrolle meinerseits Threads startet (auf die Eventhandler), und das Problem ist, dass ich weit mehr Clients plane, als das Betriebssystem mir erlaubt (schon getestet). Deshalb wäre ja normalerweise das Select-Modul so interessant.
Deine beiden Vorschläge werde ich mir anschauen, sma!

Vielen Dank euch beiden.
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Wie kommst du auf die Idee, dass [mod]asyncore[/mod] Threads startet?
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
thewulf00
User
Beiträge: 11
Registriert: Donnerstag 2. November 2006, 17:39

Ich kann mir keinen anderen Weg vorstellen, wie eine Loop, die blockierend ist, event-Handler aufruft, die wiederum in anderem Kontext laufen, als die Loop. Und das für jeden Socket separat.
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Die Handler werden im selben Kontext ausgeführt wie die Schleife.
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
thewulf00
User
Beiträge: 11
Registriert: Donnerstag 2. November 2006, 17:39

D.h. maximal ein Handler wird gleichzeitig ausgeführt? Dann verstehe ich aber nicht mehr den Sinn von "asynchron".
BlackJack

@thewulf00: Es ist leichtgewichtiger als Threads. Und man hat die ganzen Probleme nicht, die bei nebenläufigen Programmen auftreten können. Dafür eignet es sich nicht für langlaufende, rechenintensive Abläufe. Der Gewinn entsteht dann, wenn die Kommunikation über viele Verbindungen langsamer ist, als das behandeln einzelner Anfragen, weil diese Kommunikation vom Betriebssystem parallel zur Abarbeitung von Anfragen erledigt wird.
Antworten