Chat Programm

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
celloboy5
User
Beiträge: 3
Registriert: Freitag 21. Oktober 2011, 22:16

Hi
Ich habe letztens ein Chat Programm programmiert aber ich habe ein Problem. Alles funktioniert super doch wenn ich das Client Programm beende dann kommt beim Server immer eine Fehlermeldung:

Code: Alles auswählen

----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 49635)
Traceback (most recent call last):
  File "C:\Python32\lib\socketserver.py", line 581, in process_request_thread
    self.finish_request(request, client_address)
  File "C:\Python32\lib\socketserver.py", line 323, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "C:\Python32\lib\socketserver.py", line 638, in __init__
    self.handle()
  File "C:\py4kids\gallileo press\Chat\socketserver_chat_server_test.py", line 13, in handle
    s = self.request.recv(1024)
socket.error: [Errno 10054] Eine vorhandene Verbindung wurde vom Remotehost geschlossen
----------------------------------------
Und wenn ich es neu starte ohne den Sevrer neu zu starten kommt beim Server immer diese Fehlermeldung:

Code: Alles auswählen

Exception happened during processing of request from ('127.0.0.1', 49644)
Traceback (most recent call last):
  File "C:\Python32\lib\socketserver.py", line 581, in process_request_thread
    self.finish_request(request, client_address)
  File "C:\Python32\lib\socketserver.py", line 323, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "C:\Python32\lib\socketserver.py", line 638, in __init__
    self.handle()
  File "C:\py4kids\gallileo press\Chat\socketserver_chat_server_test.py", line 18, in handle
    i.request.send(bytes(text,"utf-8"))
socket.error: [Errno 10038] Ein Vorgang bezog sich auf ein Objekt, das kein Socket ist
----------------------------------------
:K

Ich schreibe mal den code vom Server und dem Client rein:

Server:

Code: Alles auswählen

# -*- coding: iso-8859-15 -*-
import socketserver
import socket
client=[]


class ChatRequestHandler(socketserver.BaseRequestHandler):
    def handle(self):
        addr = self.client_address[0]
        print("[{0}] Verbindung hergestellt".format(addr))
        client.append(self)
        while True:
            s = self.request.recv(1024)
            if s:
                print("[{0}] {1}".format(addr, s.decode()))
                text=s.decode()
                for i in client:
                    i.request.send(bytes(text,"utf-8"))
            else:
                client.remove(self)
                print("[{0}] Verbindung"
                      " geschlossen".format(addr))
                break

server = socketserver.ThreadingTCPServer(("", 50002), ChatRequestHandler)
server.serve_forever()
Client:

Code: Alles auswählen

import socket
import sys
import _thread
from time import *
from PyQt4 import QtGui, QtCore 
from GrafClient import Ui_Chat_Client as Dlg


ende=False





############################################################################
class MeinDialog(QtGui.QDialog, Dlg): 
    def __init__(self): 
        QtGui.QDialog.__init__(self) 
        self.setupUi(self)
        # Slots einrichten
        self.connect(self.Verbinden, 
                QtCore.SIGNAL("clicked()"), self.onVerbinden)
        self.connect(self.OK, 
                QtCore.SIGNAL("clicked()"), self.onAbbrechen)
        self.connect(self.Abbrechen, 
                QtCore.SIGNAL("clicked()"), self.onAbbrechen)
        self.connect(self.Senden, 
                QtCore.SIGNAL("clicked()"), self.onSenden)

    def onAbbrechen(self):
        ende=True
        self.close()
    def onVerbinden(self):
        fehler_ver=True
        try:
            global s
            ip=self.lineEdit.text()
            port=self.Port.text()
            name=self.Name.text()
            port=int(port)
            print(ip,port,name)
            s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
            s.connect((ip,port))
        except:
            fehler_ver=False
            self.Info.addItem("Verbindungsfehler!!!!")
            s.close()
        if fehler_ver:
            self.Info.addItem("Verbunden mit: "+str(ip)+"-"+str(port)+" !!!!")
    def onSenden(self):
        text=self.Text.toPlainText()
        s.send(bytes(text,"utf-8"))
        self.Text.setPlainText("")
        _thread.start_new_thread(abrufen,())

def abrufen():
    while True:
        if ende:
            s.close()
            exit()
        back=s.recv(1024)
        addr="server"
        if back:
            dialog.Chat.addItem("[{0}] {1}".format(addr, back.decode()))        

            
################################################################################
app = QtGui.QApplication(sys.argv) 
dialog = MeinDialog() 
dialog.show() 
sys.exit(app.exec_())
Kann mir jemand Helfen??

Ich weis echt nicht was ich falsch gemacht habe.

Paul

P.S. Wenn ihr noch den Code für PyQT braucht :
GrafClient:

Code: Alles auswählen

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'GrafClient.ui'
#
# Created: Wed Oct 19 21:53:12 2011
#      by: PyQt4 UI code generator 4.8.5
#
# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    _fromUtf8 = lambda s: s

class Ui_Chat_Client(object):
    def setupUi(self, Chat_Client):
        Chat_Client.setObjectName(_fromUtf8("Chat_Client"))
        Chat_Client.resize(873, 576)
        Chat_Client.setWindowTitle(QtGui.QApplication.translate("Chat_Client", "Dialog", None, QtGui.QApplication.UnicodeUTF8))
        self.groupBox = QtGui.QGroupBox(Chat_Client)
        self.groupBox.setGeometry(QtCore.QRect(10, 10, 461, 511))
        self.groupBox.setTitle(QtGui.QApplication.translate("Chat_Client", "Chat", None, QtGui.QApplication.UnicodeUTF8))
        self.groupBox.setObjectName(_fromUtf8("groupBox"))
        self.Senden = QtGui.QPushButton(self.groupBox)
        self.Senden.setGeometry(QtCore.QRect(340, 470, 101, 31))
        self.Senden.setText(QtGui.QApplication.translate("Chat_Client", "Senden", None, QtGui.QApplication.UnicodeUTF8))
        self.Senden.setObjectName(_fromUtf8("Senden"))
        self.Text = QtGui.QTextEdit(self.groupBox)
        self.Text.setGeometry(QtCore.QRect(10, 430, 321, 71))
        self.Text.setObjectName(_fromUtf8("Text"))
        self.Nr = QtGui.QTextEdit(self.groupBox)
        self.Nr.setGeometry(QtCore.QRect(340, 430, 104, 31))
        self.Nr.setObjectName(_fromUtf8("Nr"))
        self.Chat = QtGui.QListWidget(self.groupBox)
        self.Chat.setGeometry(QtCore.QRect(10, 20, 431, 391))
        self.Chat.setObjectName(_fromUtf8("Chat"))
        self.groupBox_2 = QtGui.QGroupBox(Chat_Client)
        self.groupBox_2.setGeometry(QtCore.QRect(480, 10, 381, 511))
        self.groupBox_2.setTitle(QtGui.QApplication.translate("Chat_Client", "Optionen/Infos", None, QtGui.QApplication.UnicodeUTF8))
        self.groupBox_2.setObjectName(_fromUtf8("groupBox_2"))
        self.lineEdit = QtGui.QLineEdit(self.groupBox_2)
        self.lineEdit.setGeometry(QtCore.QRect(70, 20, 191, 20))
        self.lineEdit.setObjectName(_fromUtf8("IP"))
        self.label = QtGui.QLabel(self.groupBox_2)
        self.label.setGeometry(QtCore.QRect(20, 20, 46, 13))
        self.label.setText(QtGui.QApplication.translate("Chat_Client", "IP:", None, QtGui.QApplication.UnicodeUTF8))
        self.label.setObjectName(_fromUtf8("label"))
        self.label_2 = QtGui.QLabel(self.groupBox_2)
        self.label_2.setGeometry(QtCore.QRect(20, 50, 46, 13))
        self.label_2.setText(QtGui.QApplication.translate("Chat_Client", "Port:", None, QtGui.QApplication.UnicodeUTF8))
        self.label_2.setObjectName(_fromUtf8("label_2"))
        self.Port = QtGui.QLineEdit(self.groupBox_2)
        self.Port.setGeometry(QtCore.QRect(70, 50, 191, 20))
        self.Port.setObjectName(_fromUtf8("Port"))
        self.Name = QtGui.QLineEdit(self.groupBox_2)
        self.Name.setGeometry(QtCore.QRect(70, 80, 191, 20))
        self.Name.setObjectName(_fromUtf8("Name"))
        self.label_3 = QtGui.QLabel(self.groupBox_2)
        self.label_3.setGeometry(QtCore.QRect(20, 80, 46, 13))
        self.label_3.setText(QtGui.QApplication.translate("Chat_Client", "Name:", None, QtGui.QApplication.UnicodeUTF8))
        self.label_3.setObjectName(_fromUtf8("label_3"))
        self.Verbinden = QtGui.QPushButton(self.groupBox_2)
        self.Verbinden.setGeometry(QtCore.QRect(280, 80, 75, 23))
        self.Verbinden.setText(QtGui.QApplication.translate("Chat_Client", "Verbinden", None, QtGui.QApplication.UnicodeUTF8))
        self.Verbinden.setObjectName(_fromUtf8("Verbinden"))
        self.progressBar = QtGui.QProgressBar(self.groupBox_2)
        self.progressBar.setGeometry(QtCore.QRect(20, 110, 351, 23))
        self.progressBar.setProperty("value", 24)
        self.progressBar.setObjectName(_fromUtf8("progressBar"))
        self.label_4 = QtGui.QLabel(self.groupBox_2)
        self.label_4.setGeometry(QtCore.QRect(20, 340, 46, 13))
        self.label_4.setText(QtGui.QApplication.translate("Chat_Client", "INFOS:", None, QtGui.QApplication.UnicodeUTF8))
        self.label_4.setObjectName(_fromUtf8("label_4"))
        self.Info = QtGui.QListWidget(self.groupBox_2)
        self.Info.setGeometry(QtCore.QRect(20, 360, 341, 141))
        self.Info.setObjectName(_fromUtf8("Info"))
        self.Online = QtGui.QListWidget(self.groupBox_2)
        self.Online.setGeometry(QtCore.QRect(235, 140, 131, 192))
        self.Online.setObjectName(_fromUtf8("Online"))
        self.label_5 = QtGui.QLabel(self.groupBox_2)
        self.label_5.setGeometry(QtCore.QRect(150, 150, 81, 20))
        self.label_5.setText(QtGui.QApplication.translate("Chat_Client", "Gerade Online:", None, QtGui.QApplication.UnicodeUTF8))
        self.label_5.setObjectName(_fromUtf8("label_5"))
        self.splitter = QtGui.QSplitter(Chat_Client)
        self.splitter.setGeometry(QtCore.QRect(620, 530, 231, 31))
        self.splitter.setOrientation(QtCore.Qt.Horizontal)
        self.splitter.setObjectName(_fromUtf8("splitter"))
        self.Abbrechen = QtGui.QPushButton(self.splitter)
        self.Abbrechen.setText(QtGui.QApplication.translate("Chat_Client", "Abbrechen", None, QtGui.QApplication.UnicodeUTF8))
        self.Abbrechen.setObjectName(_fromUtf8("Abbrechen"))
        self.OK = QtGui.QPushButton(self.splitter)
        self.OK.setText(QtGui.QApplication.translate("Chat_Client", "OK", None, QtGui.QApplication.UnicodeUTF8))
        self.OK.setObjectName(_fromUtf8("OK"))

        self.retranslateUi(Chat_Client)
        QtCore.QMetaObject.connectSlotsByName(Chat_Client)

    def retranslateUi(self, Chat_Client):
        pass
lunar

@celloboy5: Der kompilierte Quelltext interessiert niemanden. Wenn überhaupt, dann zeige die UI-Datei von Designer. In diesem Fall aber ist das völlig irrelevant.

Der erste Fehler entsteht wohl dadurch, dass die Verbindung nicht korrekt geschlossen wird. Der zweite Fehler entsteht in der Konsequenz daraus, da Du im Falle eines Fehlers geschlossene Verbindungen nicht aus "client" entfernst. Im Fehlerfall verbleiben geschlossene Verbindungen also endlos in "client", und der Server versucht mithin, Daten über nicht mehr existente Verbindungen zu senden.

Wo genau der Fehler liegt, kann ich Dir nicht sagen. Die Struktur des Programms ist zu konfus, um dessen Abläufe nachzuverfolgen und das Programm zu verstehen. Was in Gottes Namen hast Du Dir denn dabei gedacht, "abrufen()" als Funktion zu implementieren, die das Socket "s" über eine globale Variable erhält. Wieso ist "s" kein Exemplarattribut von "MeinDialog"? "abrufen()" könnte dann eine Methode von "MeinDialog" sein, und Du bräuchtest die ganzen globalen Variablen nicht mehr. Jede Wette, dass Du selbst nicht mehr genau weißt, wann welche dieser Variablen welchen Wert einnimmt. Folglich ist das Programm an mehreren Stellen fehlerhaft:
  • "ende" in "onAbbrechen()" ist eine lokale Variable und damit unabhängig vom "ende" in "abrufen()". Es fehlt ein "global ende".
  • Das unbedingtet "except" in onVerbinden fängt auch Fehler ab, die mit dem Socket überhaupt nichts zu tun haben, u.a. auch mögliche "NameError", die entstehen, wenn Du Dich bei einer Variable vertippt hast. Verwende niemals ein "except" ohne konkrete Ausnahme!
  • Der Unterstrich im Namen von "_thread" bedeutet, dass dieses Modul privat ist. Die Dokumention rät mithin auch explizit davon ab, es zu benutzen. Nutze stattdessen "threading".
  • "abrufen()" läuft in einem eigenen Thread, greift aber dennoch auf die Oberfläche zu. Das ist in Qt nicht erlaubt, und kann alle möglichen Fehler bis hin zu kommentarlosen Abstürzen des Programms zur Folge haben.
Meines Erachtens ist dieses Programm in seiner jetztigen Form nicht zu retten. Selbst wenn Du die obigen Fehler beseitigst, so baust Du ob der konfusen Struktur mit Sicherheit weitere ein. Schreibe das Programm neu, ohne global. Dabei ist es ratsam, die Qt-Klassen für Sockets zu nutzen, da diese Signale und Slots unterstützen. Dann wird "abrufen" hinfällig. Dafür habe ich mal ein Beispiel geschrieben.
celloboy5
User
Beiträge: 3
Registriert: Freitag 21. Oktober 2011, 22:16

Hi
Danke für deine Antwort.

Gut du musst wissen ich arbeite mit Python noch nicht sehr lange (ich lerne das noch). ICh habe schon ein paar von deinen Tipps eigebaut und werde das Programm warscheinlich neu schreiben.

Aber ich habe noch zwei Fragen.

1. Was hältst du von dem Server kann man da was besser machen?
2. Ich verstehe leider nicht ganz genau was du mit PYQT und dem Socket meinst. Kannst du das nochmal für "Anfänger" erklären?

Das ist echt nett!!

Gruß Paul
lunar

@celloboy5: Die "client"-Liste sollte nicht auf Modul-Ebene, sondern im Server-Objekt verwaltet werden. Dazu solltest Du eine eigene, vom ThreadingTCPServer abgeleitete Klasse erstellen.

Zu Qt und Sockets habe ich Dir ein Beispiel gegeben. Konkrete Frage zu diesem Beispiel kann ich Dir beantworten, doch für allgemeine Tutorien zu Qt und Sockets gibt es die offizielle Dokumentation.
celloboy5
User
Beiträge: 3
Registriert: Freitag 21. Oktober 2011, 22:16

Hi

Ja das Beispiel habe ich gesehen. Aber erlich gesagt ist das ein bischen kompliziert für mich. Ich würde mir dein Progrsmm gerne mal anschauen (Damit ich es besser verstehe). Nun gibt mir das Progamm aber immer eine Fehlermeldung aus. Für welche Python version ist das?

Und könnte ich daas Programm auch ohne die Slots Network funktion von PyQt schreiben und dann vieleicht Tkinter benutzen?

Paul
lunar

@celloboy5: Das Programm ist für Python 2 und PySide.

Für Tkinter benötigst Du in jedem Fall Threads.
Antworten