Problem Datenübertragung (Variablen-Typ)

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Benutzeravatar
spicer
User
Beiträge: 52
Registriert: Freitag 5. März 2021, 23:40
Kontaktdaten:

Hallo Gemeinde. Ich stehe gerade gehörig auf dem Schlauch.
Ich code ein Game und will einen Server erstellen, wo sich Clients anmelden können.
Ich sende eine Liste mit den Clients (Usern), welche momentan online sind an den/die Clients.

Serverseitig:

Code: Alles auswählen

def send_clients_list(server_msg,c):
    for i in range(len(server_msg)):
        print("an client gesendet: ", server_msg[i], i, type(server_msg))
        c.send("clients".encode() + server_msg[i])
Das Präfix "clients" sagt den Clients, das es sich um eine Userliste handelt.

Clientseitig:

Code: Alles auswählen

print("from_server:", from_server)
if from_server.startswith("clients".encode()):                                 
    clients_names.clear()                                                      
    clients_names.append(from_server.replace("clients".encode(), "".encode())) 
    update_client_names_display(clients_names)  # update client names display  

Nach der Anmeldung von 3 Clients, sieht der "Print-Output" des Servers wie folgt aus:

Server Output:

Code: Alles auswählen

an client gesendet:  b'aaa' 0 <class 'list'>

an client gesendet:  b'aaa' 0 <class 'list'>
an client gesendet:  b'bbb' 1 <class 'list'>

an client gesendet:  b'aaa' 0 <class 'list'>
an client gesendet:  b'bbb' 1 <class 'list'>
an client gesendet:  b'ccc' 2 <class 'list'>

Ab der Anmeldung vom dritten Client, sieht der "Print-Output" der Clients wie folgt aus:

Client Output:

Code: Alles auswählen

from_server: b'clientsaaa'

from_server: b'clientsaaa'
from_server: b'clientsbbb'

from_server: b'clientsaaa'
from_server: b'clientsbbbclientsccc'
Ich vermute, ich müsste iwie ein Trennzeichen senden, damit ab den dritten Client nicht alles aneinander gehängt wird.
Habe aber nach Stunden pröbeln keinen Plan mehr.
Sehe ich das richtig, dass clients_names eigentlich ein Array mit Strings sein sollte?
Ich habe den Durchblick verloren.
Vllt kann mir ja jemand helden.
Wenn es mehrere Möglichkeiten gibt, eine Aufgabe zu erledigen, und eine davon in einer Katastrophe endet oder sonstwie unerwünschte Konsequenzen nach sich zieht, dann wird es jemand genau so machen. Alles, was schiefgehen kann, wird auch schiefgehen.
(Murphys Gesetz)
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Endlich mal ein Beispiel, wo man mit fehlerhaftem socket Code tatsächlich sofort auf die Nase fällt. 99,999% aller Beispiele zur Socket-Programmierung, die Du im Internet findest, sind fehlerhaft oder zu einfach, dass man nichts damit anfangen kann.
Ja, Du brauchst ein Trennzeichen, am besten ein bereits bestehendes Protokoll, das für deinen Zweck geeignet ist, was bei Spielen ganz spezielle Anforderungen sein können.

Sonstige Anmerkungen zum Code: über einen Index iteriert man nicht, weil man einfacher direkt über die Elemente von server_msg iterieren kann.
server_msg ist ein schlechter Variablenname, weil er ja eigentlich eine Liste von Client Namen enthält, was viel spezifischer ist als nur eine beliebige Servernachricht. "c" ist eine schlechte Bezeichnung für einen client_socket.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn man das wirklich alles selbst machen will, sollte man `makefile` verwenden.
Das könnte zum Beispiel so aussehen:

Code: Alles auswählen

file = client_socket.makefile("rwb")

# server send
data = json.dumps(usernames).encode()
file.write(b"%08d%s" % (len(data), data))

# client recv
length = int(file.read(8))
data = file.read(length)
usernames = json.loads(data)
Benutzeravatar
spicer
User
Beiträge: 52
Registriert: Freitag 5. März 2021, 23:40
Kontaktdaten:

Erst mal vielen Dank Sirius3
Du schreibst "Wenn man das wirklich alles selbst machen will". Gibt's denn da fertige Programmschnipsel oder Libraries?
Wenn es mehrere Möglichkeiten gibt, eine Aufgabe zu erledigen, und eine davon in einer Katastrophe endet oder sonstwie unerwünschte Konsequenzen nach sich zieht, dann wird es jemand genau so machen. Alles, was schiefgehen kann, wird auch schiefgehen.
(Murphys Gesetz)
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Alles moegliche. Ich benutze zB gerne nanomsg bzw. den Nachfolger nng um mich von den Muehen der Netzwerkeben zu befreien. Damit bekommst du auch gleich Topologien wie zB ein Bus - eine Nachricht erreicht automatisch eine ganze Reihe von Empfaengern - oder broadcasts etc. ZeroMQ ist eine andere Alternative. Beide sind message-orientiert, so, wie die meisten Leute ueber Sockets denken - nur dass die das nicht sind, sonder Stream-basiert, und dann kommt es zu solchen Fehlannahmen wie von dir hier. Aber auch Websockets oder HTTP eigenen sich.

Und fuer das Format der Nachrichten nimmt man sinnvollerweise sowas wie JSON, statt sich da muehselig eigene Formate auszudenken, die man dann parsen und erzeugen muss.

Zu guter Letzt gibt es auch noch sowas wie https://github.com/irmen/Pyro4 - damit arbeitet man dann gleich so, als ob die verschiedenen Python-Interpreter deines Spiels Objekte und Methoden der jeweils anderen zur Verfuegung haben.
Benutzeravatar
spicer
User
Beiträge: 52
Registriert: Freitag 5. März 2021, 23:40
Kontaktdaten:

Sirius3 hat geschrieben: Sonntag 20. Februar 2022, 10:14 Wenn man das wirklich alles selbst machen will, sollte man `makefile` verwenden.
Das könnte zum Beispiel so aussehen:

Code: Alles auswählen

file = client_socket.makefile("rwb")

# server send
data = json.dumps(usernames).encode()
file.write(b"%08d%s" % (len(data), data))

# client recv
length = int(file.read(8))
data = file.read(length)
usernames = json.loads(data)
Funktioniert das bei Dir?
Es scheint, dass der Server sendet. Aber der Client hält die Füsse still.
Wenn es mehrere Möglichkeiten gibt, eine Aufgabe zu erledigen, und eine davon in einer Katastrophe endet oder sonstwie unerwünschte Konsequenzen nach sich zieht, dann wird es jemand genau so machen. Alles, was schiefgehen kann, wird auch schiefgehen.
(Murphys Gesetz)
Benutzeravatar
spicer
User
Beiträge: 52
Registriert: Freitag 5. März 2021, 23:40
Kontaktdaten:

Ok, beim Server mit

Code: Alles auswählen

client_socket.send(b"%08d%s" % (len(data), data))
läuft's ^^
Wenn es mehrere Möglichkeiten gibt, eine Aufgabe zu erledigen, und eine davon in einer Katastrophe endet oder sonstwie unerwünschte Konsequenzen nach sich zieht, dann wird es jemand genau so machen. Alles, was schiefgehen kann, wird auch schiefgehen.
(Murphys Gesetz)
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Es könnte sein, dass es ein file.flush() braucht. `send` ist falsch, weil es nicht garantiert, dass alle Bytes gesendet werden, wie es ja auch deutlich in der Dokumentation steht.
Benutzeravatar
spicer
User
Beiträge: 52
Registriert: Freitag 5. März 2021, 23:40
Kontaktdaten:

Also nach file.write(... ein file.flush() ?
Wenn es mehrere Möglichkeiten gibt, eine Aufgabe zu erledigen, und eine davon in einer Katastrophe endet oder sonstwie unerwünschte Konsequenzen nach sich zieht, dann wird es jemand genau so machen. Alles, was schiefgehen kann, wird auch schiefgehen.
(Murphys Gesetz)
Antworten