Frage zu asynchat, vielleicht auch einfach nur Python

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Bersaelor
User
Beiträge: 7
Registriert: Dienstag 9. März 2010, 00:28
Kontaktdaten:

Hallo,

ich möchte einen einfachen Frage/Antwort Server schreiben auf dem sich clients über feste sockets anmelden können.

Das funktioniert mit dem asyncore service/dispatcher modell ganz gut, ich erstelle einen asyncore dispatcher der die einzelnen "service" als Tochterklasse von asynchat erstellt, die dann auf Nachrichten der jeweiligen Clients reagieren.

D.h. durch überladen der Methoden "found_terminator(self):" und "self.push(self,data):) kann ich wunderbar Daten empfangen bzw. senden.
Im wesentlichen läuft das so ab dass wenn eine Nachricht reinkommt der Server dem jeweiligen Client eine Antwort schickt.

Nun würde ich aber gern, wenn ein Client z.B. eine neue Textzeile in einem Chat schickt, diese nicht nur dem derzeitigen Chat-Array "appenden" sondern auch die anderen clients, die sich per "Listen to Chat" gemeldet haben, über die neue Nachricht informieren.

Ich hatte erst gedacht, ich erstelle eine globale Liste "ChatListeners" und alle Clients die sich zum Chat-listenening anmelden wird dann weitergeleitet.

Code zum registrieren:

Code: Alles auswählen

		elif data.startswith('Get chats'):
			self.newPush(''.join(['JSON:Chat:',
			json.dumps(chatList, separators=(',',':'))]))
			#register this instance as a listener for new chat messages
			chatListeners.append(self);
Das heißt wenn die neue Nachricht kommt, müsste ich dann

Code: Alles auswählen

			for service in chatListeners:
				service.newPush(newMsg)
Wenn ich dies aber ausführe erhalte ich die folgende Exception:

Code: Alles auswählen

error: uncaptured python exception, closing channel <__main__.Service 
connected 85.178.233.245:15886 at 0x7fc1ad9a6200> 
(<class 'socket.error'>:(9, 'Bad file descriptor') [/usr/lib/python2.5
/asynchat.py|initiate_send|219] [/usr/lib/python2.5/asyncore.py|send|331] 
[/usr/lib/python2.5/socket.py|_dummy|146])
In C/Objektive C wüsste ich wie ich das machen würde, da würde ich den Zeiger auf das jeweilige objekt vom typ "service" in eine Liste packen und dann beim durchgehen der liste vom einem standardzeiger auf die Klasse "service" casten.

Wie würde ich das denn jetzt in Python machen? Vielen Dank für Hilfe![/code]

EDIT: Bevor jemand sich wundert, die methode newPush ist einfach eine Überladung der Methode Push damit der Client bestimmen kann wann eine Nachricht zu ende ist:

Code: Alles auswählen

class Service(asynchat.async_chat):

	def __init__(self, server, sock):
		asynchat.async_chat.__init__(self, sock)
		self.set_terminator('\r\n')
		self.data = ''

	def collect_incoming_data(self, data):
		print "Current data :",self.data
		self.data = self.data + data

	def newPush(self, data):
		self.push(''.join( [data,'\r\n']))

#....
Zuletzt geändert von Bersaelor am Dienstag 9. März 2010, 15:38, insgesamt 1-mal geändert.
[url=http://www.tactica.de/]Tactica-hexagonale Strategie fürs iPhone[/url]
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Bersaelor hat geschrieben: Das heißt wenn die neue Nachricht kommt, müsste ich dann

Code: Alles auswählen

			for service in chatListeners:
				service.newPush(newMsg)
In C/Objektive C wüsste ich wie ich das machen würde, da würde ich den Zeiger auf das jeweilige objekt vom typ "service" in eine Liste packen und dann beim durchgehen der liste vom einem standardzeiger auf die Klasse "service" casten.

Wie würde ich das denn jetzt in Python machen? Vielen Dank für Hilfe!
Das hast du schon richtig umgesetzt. 'Bad filedescriptor' von der Socket-API heisst, dass die Gegenseite keine Daten (mehr) empfangen mag, z.B. weil die Verbindung schon geschlossen wurde. Ich hab jetzt asynchat nicht mehr so genau im Kopf und auch gerade wenig Zeit, aber vlt. hilfts trotzdem...

PS: Kannst du bitte die langen Codezeilen umbrechen, das vermurkst das Layout total... Danke!
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Bersaelor
User
Beiträge: 7
Registriert: Dienstag 9. März 2010, 00:28
Kontaktdaten:

Stimmt, es lag scheinbar an einer Verbindungssache.

Wenn das so erstmal richtig ist, wie würdet ihr die Services wieder aus der Liste herausnehmen?

D.h. wenn jemand disconnected wird die methode "handle_close" der instanz aufegrufen. Die könnte ich ja überladen und müsste irgendwie "self" aus der Liste "chatListeners" herausnehmen.

Oder soll ich die Liste als Dictionary machen, in dem key=object=self ist?

PS: Codeumbruchzeilen kommt nicht wieder vor!
[url=http://www.tactica.de/]Tactica-hexagonale Strategie fürs iPhone[/url]
Antworten