unregelmäßiger Socket Absturz Errno 104

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Hanebampel
User
Beiträge: 2
Registriert: Dienstag 28. März 2017, 19:13

Hallo zusammen,

zu Anfang muss ich sagen das ich absoluter Anfänger bin.
Ich habe mir folgenden Code zusammengebastelt.
Hab Ihn mal auf das wichtigste zusammengeschrumpft.

Jetzt habe ich das Problem das er irgendwann mit der Fehlermeldung
„ConnectionResetError: Errno 104 Connection reset by peer“ abbricht.

Das ist aber total unregelmäßig. Manchmal läuft er Tage ohne Probleme.
Wie kann ich den Fehler abfangen und den Socket wieder starten.

Ich habe sowas von keiner Ahnung. Hoffe Ihr könnt mir irgendwie mit einem Tipp oder Beispiel helfen.
Danke
Hanebampel

Code: Alles auswählen

#!/usr/bin/python3.4
#----------------------------------------------------------------

import threading
import socket
from tkinter import *                                      

#------ TCP/IP Start------
MeinSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

def socket():
    try:
        MeinSocket.bind(("", 50000))
        MeinSocket.listen(1)
        while True:
            PartnerSocket, addr = MeinSocket.accept()
            while True:
                daten = PartnerSocket.recv(1024)
                if not daten:
                    PartnerSocket.close()
                    break
                AusgabeTCP.insert(END, "Empfange:  [%s] %s" % (addr[0], daten))                       
                AusgabeTCP.insert(END, " \n")                                                     

                if b'!TEST' in daten:
                    print ("mach was")
    except:
        print("Fehler im Socket")
    finally:
        MeinSocket.close()
#------ TCP/IP Stop------



#Tkinter Hauptformular Ausgabe anfang----------------
window = Tk(className=" Test Steuerung")                                          
Ausgabe = Text(master=window, width = 50, height = 30, wrap=WORD)
AusgabeTCP = Text(master=window, width = 70, height = 30, wrap=WORD)
window.geometry('1400x280')
Ausgabe.pack(side=LEFT)
AusgabeTCP.pack(side=LEFT)
#Tkinter Hauptformular Ausgabe ende------------------


StartSocket = threading.Thread(target=socket)
StartSocket.start()

window.mainloop()
Zuletzt geändert von Anonymous am Dienstag 28. März 2017, 20:21, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@Hanebampel: *Den* Socket? Welchen denn? Wenn Du eine vernünftige Fehlerbehandlung machen würdest, also nur die Ausnahmen behandeln die Du tatsächlich erwartest und behandeln kannst, und dann auch an der richtigen Stelle, also nicht einfach über *alles*, dann sollte das Serversocket erhalten bleiben.

Wenn die Verbindung zum gegenüber abbricht weil das gegenüber die Verbindung kappt, dann kannst Du nichts machen. Der Server kann keine Verbindungen aufbauen, das ist Aufgabe des Clients. Und wenn der die Verbindung kappt ist das entweder gewollt (von ihm) oder sein Problem.
Hanebampel
User
Beiträge: 2
Registriert: Dienstag 28. März 2017, 19:13

Sorry, habe überall gelesen das das Socket heißt. Das Modul was ich Importiere nennt sich ja auch so.

Um die Fehlerbehandlung geht es mir ja. Ich weiß nicht wie ich das mache das es weiter Funktioniert.
Das der Server keine Verbindung aufbaut ist klar. Aber wenn der Client aus irgendeinem Grund diese kappt
muss doch der Server weiterlaufen und auf neue Verbindungen warten können.

Dass mit der Richtigen Stelle und "über alles" habe ich auch nicht Verstanden

Danke für eure Hilfe
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Hanebampel: bei Dir heißt vieles Socket, was auch gar kein Socket ist. Außerdem hältst Du Dich nicht an die übliche Namenskonvention (Variablen klein geschrieben, nur Klassen mit großem Anfangsbuchstaben), so dass das Lesen sehr erschwert wird. Was soll bei MeinSocket das Mein heißen? Und warum wird der Socket außerhalb der Server-Funktion geöffnet? Warum überschreibt die Funktion socket das Modul socket und warum heißt die überhaupt so? Warum heißt ein Thread StartSocket? Aus einem Thread heraus sollte man die GUI nicht verändern. Das kann zu nicht nachvollziehbaren Fehlern führen.
Was für ein Fehler im Server passiert kannst Du gar nicht sehen, weil Du jeden Fehler durch "Fehler im Socket" ersetzt. Um das also sinnvoll Debuggen zu können, muß das except weg. Das nakte except führt sogar soweit, dass einfache Tippfehler den Server mit "Fehler im Socket" abbrechen lassen.
Dein recv kann bis zu 1024 Bytes zurückliefern, im Extremfall aber nur ein Byte nach dem anderen, was zu hunderten Emfange-Nachrichten führt und den Test auf "!TEST" nie erfolgreich werden läßt, obwohl der Client "!TEST" schickt.

Eine sinnvolle Fehlerbehandlung würde die Fehler, die während der Verarbeitung der Client-Verbindung auftreten auch dort behandeln, im Zweifel mit der generellen Exception und einem logging.exception.
BlackJack

@Hanebampel: Das hervorgehobene *Den* war nicht grammatikalisch oder auf einen falschen Namen bezogen gemeint, sondern bezog sich auf die *Anzahl*. Du hast da *zwei* Sockets und die Fehlerbehandlung bezieht sich auf *beide* wo Du aber nur *einen* von beiden behandeln möchtest. Denn bei beiden wird bei einer Ausnahme die gesamte ``while``-Schleife verlassen weil der ``try``-Block *alles* in der Funktion `socket()` umfasst, und nicht nur den Teil des Codes in dem Probleme mit dem Socket auftreten können bei dem der Client überhaupt die Verbindung kappen kann. Wenn man sich auf den Teil beschränken würde, dann würde auch die ``while``-Schleife greifen und wieder auf den nächsten Verbindungswunsch eines Clients warten.

Man sollte ausserdem nicht Programmlogik und Benutzerinteraktion vermischen. Der GUI-Kram hat in einer Funktion die mit Sockets kommuniziert nichts zu suchen. Zudem veränderst Du aus einem anderen Thread als dem in dem die Hauptschleife der GUI läuft, die GUI, was keine gute Idee ist. Das kann funktionieren, muss es aber nicht. Ih würde die GUI erst einmal weg lassen und mich auf den Socket-Code konzentrieren. Wenn der dann korrekt ist, kann man immer noch Threads und GUI dazu tun.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Also keine Variablen und vor allem auch nicht Variablen und Funktionsdefinitionen gemischt. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst. Wenn man das so macht, dann ergibt sich daraus auch, das man in Funktionen nicht auf magische Weise auf Variablen im Modul zugreifen kann, was Sirius3 ja schon angesprochen hat. Werte betreten Funktionen und Methoden dann als Argumente, so dass man erkennen kann auf was eine Funktion zugriff braucht, ohne sie komplett zu lesen, und man sie auch einfacher testen kann, weil sie von nichts abhängt was nicht übergeben werden kann.
Antworten