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!
Socketüberwachung mit vielen Clients
select.select funktioniert doch, ich hab mal nen kleinen Chat geschriben:
Ungetestet! mein Chat funktioniert zwar, allerdings ist das nur 'rauskopiert'
mfg
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()
mfg
the more they change the more they stay the same
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
Stefan
@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.
@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.
@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.