Socket im Dictionary abspeichern

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
schabi
User
Beiträge: 6
Registriert: Donnerstag 8. Februar 2018, 12:45

Hallo,
ich wollte angeneommene Sockets in einem Dictionary speichern und später wieder darauf zugreifen um diesen z.B. Nachrichten zusenden zu können.
Jedoch beendet Python sich mit dem Fehlercode 1.
Könntet Ihr mir sagen was ich falsch gemacht habe?

Danke :)

Code: Alles auswählen

# Socketannahme
connection, addr = sock.accept()
# ich lasse mir dann vom "Client" einen Nutzernamen mitteilen
self.Clients.update({nutzername: [connection]})

# Ergebnis->
test [<socket.socket fd=1052, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 3012), raddr=('127.0.0.1', 60351)>]
später wollte ich dann so auf das Socket zugreifen und "Daten" senden, da jedoch flieg ich dann raus :K

Code: Alles auswählen

        for name, verbindung in self.Clients.items():
            verbindung.sendall("ENDE".encode())
            print("Verbindung mit {} beendet.".format(name))
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@schabi: zeig Deinen Code und den kompletten Traceback. So wie Du das beschreibst, kann es nämlich nicht sein, Du bekommst einen AttributeError, weil eine Liste kein »sendall« kennt. Warum überhaupt die Liste. Einzelne Werte weißt man einem Dictionary über den Indexzugriff zu, nicht mit »update«.
schabi
User
Beiträge: 6
Registriert: Donnerstag 8. Februar 2018, 12:45

Update Manchmal sieht man den Wald vor lauter Bäumen nicht. Natürlich hatte Sirius3 absolut recht das eine liste den sendall Befehl nicht kennt. Mein Fehler war das ich es beim abspeichern in eine Liste gecastet habe :oops:

Code: Alles auswählen

# falsch
self.Clients.update({nutzername: [connection]})
# richtiger ->
self.Clients.update({nutzername: connection})
Sirius3 hat geschrieben:@schabi: ... Du bekommst einen AttributeError, weil eine Liste kein »sendall« kennt ....
das habe ich fast befürchtet, nur fürs verständnis -> wenn ich die "connection" in das Dictionary sende ist es quasi kein socket mehr?

Wie kann ich denn das zurückcasten?
Sirius3 hat geschrieben:Einzelne Werte weißt man einem Dictionary über den Indexzugriff zu, nicht mit »update«.
das hatte ich von google/stackoverflow ( https://stackoverflow.com/questions/102 ... dictionary )

Sirius3 hat geschrieben:@schabi: zeig Deinen Code und den kompletten Traceback.
Der Code ist leider noch nicht aufgehübscht, da ich noch lerne und viel rumteste. :oops:

Code: Alles auswählen

class MultiplexServer(QtCore.QThread):
    def __init__(self, parent, ip="", port=3012,):
        super(MultiplexServer, self).__init__(parent)
        self.IP = ip
        self.Port = port
        self.Clients = {}
        self.Events = eigene_events
        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.selector = selectors.DefaultSelector()
        self.lauf = True
        self.lcheck = listenchecker(self, self.selector)


    def Hochfahren(self):
        self.server.bind((self.IP, self.Port))
        self.server.setblocking(False)
        self.server.listen()
        self.selector.register(self.server, selectors.EVENT_READ, self.accept)
        self.Events.eventNachricht.emit("Server auf {}:{} gestartet".format(self.IP, self.Port))


    def accept(self, select, sock):
        connection, addr = sock.accept()
        # Nutzeridentifizierung
        self.Events.eventNachricht.emit("Verbindungsversuch von [{}] / {}".format(connection, addr))
        connection.setblocking(True)
        nutzername = connection.recv(1024)
        self.Events.eventNachricht.emit("[{}] will sich mit folgendem [TAG] anmelden: {}".format(connection, nutzername.decode()))
        # TODO hier weitere Authentiizierung einbauen
        connection.sendall("True".encode())
        # Meldung an die GUI und Übergabe an den Selector
        self.Events.eventNachricht.emit("[{}] Verbindung akzeptiert!".format(addr[0]))
        # Ablegen auf den Selector
        connection.setblocking(False)
        select.register(connection, selectors.EVENT_READ, self.message)
        nutzername = nutzername.decode()
        self.Clients.update({nutzername: [connection]})
        self.Events.eventneuerNutzer.emit(addr[0], nutzername)


    def zeigeverbundeneClients(self):
        for client in self.Clients:
            #self.Events.eventNachricht.emit(client.values())
            print(client, self.Clients[client])


    def message(self, selector, client):
        nachricht = client.recv(1024)
        nachricht = nachricht.decode()
        ip = client.getpeername()[0]
        if nachricht:
            self.Events.eventNachricht.emit("Nachricht von [{}]: {}".format(ip, nachricht))
            if nachricht == "ENDE":
                selector.unregister(client)
                client.sendall("OK, machs gut. Bis zum nächsten Mal".encode())
                for name, verbindung in self.Clients.items():
                    print("verbindung: {};\n client = {}".format(verbindung[0], client))
                    print(name, self.Clients[name])
                    if str(verbindung[0]) == str(client):
                        self.Events.eventNachricht.emit("Verbindung von {} [{}] beendet. ".format(name, verbindung))
                        del self.Clients[name]
                        break

                client.close()


    def Serverstop(self):
        for name, verbindung in self.Clients.items():
            socket.socket.sendto(verbindung[0],"ENDE".encode())
            # verbindung.sendall("ENDE".encode())
            print("Verbindung mit {} beendet.".format(name))
        self.lcheck.stop()
        self.server.close()


    def run(self):

        self.lcheck.start()


class listenchecker(QtCore.QThread):
    def __init__(self, parent, selector):
        super(listenchecker, self).__init__(parent)
        self.Selector = selector
        self.lauf = True

    def stop(self):
        self.lauf = False

    def run(self):
        while self.lauf:
            for key, mask in self.Selector.select():
                key.data(self.Selector, key.fileobj)

Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

schabi hat geschrieben:das hatte ich von google/stackoverflow
Und deshalb nimmt man die vierte „Lösung“ und nicht die erste.

»MultiplexServer« nutzt gar keine Thread-Eigenschaften. Und was ist dann der Sinn, Teile der Funktionalität in eine weitere Klasse »listenchecker« auszulagern, die gar keinen eigenen Zustand hat?
»eigene_events« ist nicht definiert. Wenn man select benutzt, ist es unsinnig, den Socket auf non-blocking zu setzen.

Bei TCP handelt es sich um Streams, irgendwelche Bytes zu lesen und zu hoffen, dass das schon das richtige Liefert, ist zu optimistisch. Das wird noch zusätzlich komplexer, wenn man select benutzt, dann ist ein »sendall« eigentlich auch nicht optimal. »sendto« funktioniert mit TCP auch nicht.

Ohne ein ordentliches Protokoll wird das nichts.
Antworten