PyChat 1.0

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
Unzi
User
Beiträge: 5
Registriert: Montag 6. Februar 2006, 15:24
Wohnort: Erfurt, Thüringen
Kontaktdaten:

Montag 6. Februar 2006, 18:47

Hallo,

dieses wunderschöne Chatprogramm diente dazu, die Netzwerktutorials, die ich gelesen hatte, in die Tat umzusetzen. Es gibt nur drei kleine Probleme:

1. Wenn ich eine Nachricht absende, wird sie manchmal zweimal angezeigt. Alle von mir durchgeführten Debugging-Maßnahmen (mit denen der Code inzwischen gespickt ist) führten zu keinem sinnvollen Ergebnis.
2. Wenn ich auf "Stop Server" bzw. "Disconnect" klicke, beendet sich der Thread mit der asyncore.loop()-Schleife nicht, obwohl alle Channels (Client und Server) geschlossen sind.
3. Ich kenne keinen echten Separator (Spacer) für Tkinter, wie man auch im Code nachlesen kann.

Ich bin dankbar für jeden Hinweis. Hier der Code:

main.py:

Code: Alles auswählen

# Simple chat application with Python and Tkinter
# (c) 2006 by Martin Unzner
# http://m-unzner.de.vu
# -----------------------------------------------
# MAIN WINDOW

from Tkinter import *
from server import ChatServer
from client import ChatClient
import thread
import asyncore

class ChatWindow:
    # Class that handles the controls of the chat program
    def __init__(self,mainwnd):
        #Initialising basic variables
        self.status=0 #means Client
        self.started=0 #if the connection has already started

        Label(mainwnd,text="Welcome to PyChat, written by Martin Unzner, http://m-unzner.de.vu.").grid(column=0,row=0,columnspan=2)
        self.lClSrv=Label(mainwnd,text="Select if the program should be client or server:")
        self.lClSrv.grid(column=0,row=1,columnspan=2)
        self.cSrv=Radiobutton(mainwnd,text="Server",value=0,command=self.serverGUI)
        self.cSrv.grid(column=0,row=2)
        self.cCl=Radiobutton(mainwnd,text="Client",value=1,command=self.clientGUI)
        self.cCl.select()
        self.cCl.grid(column=1,row=2)

        Label(mainwnd,text="_______________________________________________________").grid(column=0,row=3,columnspan=2)
        # Pseudo-Separator: if anyone knows how the real one is called, please tell me

        Label(mainwnd,text="Host:").grid(column=0,row=4)
        self.hostVar=StringVar(mainwnd) #must be saved because it will be deactivated when changed to "server"
        self.eHost=Entry(mainwnd,textvariable=self.hostVar)
        self.eHost.grid(column=1,row=4)
        Label(mainwnd,text="Port:").grid(column=0,row=5)
        self.portVar=StringVar(mainwnd)
        Entry(mainwnd,textvariable=self.portVar).grid(column=1,row=5)
        self.portVar.set("10000")
        self.bStartSock=Button(mainwnd,text="Connect to server",command=self.startSock)
        self.bStartSock.grid(column=0,row=6,columnspan=2)
        
        Label(mainwnd,text="_______________________________________________________").grid(column=0,row=7,columnspan=2)

        Label(mainwnd,text="Nickname:").grid(column=0,row=8)
        self.nickVar=StringVar(mainwnd)
        Entry(mainwnd,textvariable=self.nickVar).grid(column=1,row=8)
        Label(mainwnd,text="Enter your message here:").grid(column=0,row=9)
        self.msgVar=StringVar(mainwnd)
        eMsg=Entry(mainwnd,textvariable=self.msgVar)
        eMsg.bind("<Key-Return>",self.sendMessage)
        eMsg.bind("<Key-KP_Enter>",self.sendMessage)
        eMsg.grid(column=1,row=9)
        Button(mainwnd,text="Send",command=self.sendMessage).grid(columnspan=2)
        Label(mainwnd,text="Chat Protocol:").grid(column=0,row=11,columnspan=2)
        self.tProtocol=Text(mainwnd)
        self.tProtocol.grid(column=0,row=12,columnspan=2,rowspan=5)

    def networkLoop(self,dummy1,dummy2):
        asyncore.loop(5)
        
    def startSock(self):
        if not self.started:
            host=self.hostVar.get()
            try:
                port=int(self.portVar.get())
            except:
                self.setText("No valid port number entered. Assuming 10000.","window.startSock")
                self.portVar.set("10000")
                port=10000

            bTextSet=0
            if self.status: #if selected server mode, status is 1 -> true
                try:
                    self.server=ChatServer(port,self)
                except:
                    return # no sucessful initialisation -> exiting
                host="localhost"
                self.bStartSock["text"]="Stop server"
                bTextSet=1

            try:
                self.client=ChatClient(host,port,self)
            except:
                return # no sucessful initialisation -> exiting
            #starting a thread, therefor needing at least two dummy arguments
            thread.start_new_thread(self.networkLoop,(0,0))
            if not bTextSet:
                self.bStartSock["text"]="Disconnect"
            self.cSrv["state"]=DISABLED
            self.cCl["state"]=DISABLED
            self.started=1
        else:
            self.client.close()
            self.bStartSock["text"]="Connect to server"
            if self.status:
                self.server.close()
                self.bStartSock["text"]="Start server"
            self.cSrv["state"]=NORMAL
            self.cCl["state"]=NORMAL
            self.started=0
        
    def serverGUI(self):
        self.status=1 #means Server
        self.bStartSock["text"]="Start server"
        self.eHost["state"]=DISABLED
        
    def clientGUI(self):
        self.status=0 #means Client
        self.bStartSock["text"]="Connect to server"
        self.eHost["state"]=NORMAL
        
    def sendMessage(self,ev=None):
        try:
            self.setText(self.nickVar.get()+": "+self.msgVar.get())
            self.client.sendMsg(self.nickVar.get()+": "+self.msgVar.get())
        except:
            self.setText("ERROR: You have to be connected to a server if you want to send messages.","window.sendMessage")

    def setText(self,text,f_name=None):
        if f_name:
            text=f_name+": "+text
        self.tProtocol.insert(END,text+"\n")

if __name__=="__main__":
    root=Tk()
    root.title("PyChat 1.0")
    
    ChatWindow(root)

    root.mainloop()
server.py:

Code: Alles auswählen

# Simple chat application with Python and Tkinter
# (c) 2006 by Martin Unzner
# http://m-unzner.de.vu
# -----------------------------------------------
# SERVER MODULE

import asynchat
import asyncore
import socket

class Connector(asynchat.async_chat):
    # Class that handles the connection to a specific client
    def __init__(self,server,conn):
        asynchat.async_chat.__init__(self,conn)
        self.set_terminator("\n")
        self.server=server
        self.buf=""

    def collect_incoming_data(self,data):
        self.buf+=data

    def found_terminator(self):
        #send the received data to all clients
        i=0
        for client in self.server.clients:
            i=i+1
            client.push("Server connector push: "+self.buf+"\n")
        self.buf=""

    def handle_close(self):
        self.close()

class ChatServer(asyncore.dispatcher):
    # Class that represents a server
    def __init__(self,port,main):
        asyncore.dispatcher.__init__(self)
        self.main=main
        self.clients=list() #Server stores all clients
        self.create_socket(socket.AF_INET,socket.SOCK_STREAM)
        try:
            self.bind(("localhost",port))
        except:
            main.setText("Port %d is already in use." % port,"server.init")
            raise
        self.listen(1) #waiting for new clients

    def handle_accept(self):
        conn,addr=self.accept()
        self.main.setText("SERVER: Client connected at %s" % addr[0],"server.handle_accept")
        client=Connector(self,conn)
        self.clients.append(client)

    def handle_close(self):
        for c in clients:
            c.close() #close every client that is saved in the list
        self.close()
client.py

Code: Alles auswählen

# Simple chat application with Python and Tkinter
# (c) 2006 by Martin Unzner
# http://m-unzner.de.vu
# -----------------------------------------------
# CLIENT MODULE

import asynchat
import socket

class ChatClient(asynchat.async_chat):
    # Class that handles the connection to the server
    def __init__(self,host,port,main):
        conn=socket.socket()
        try:
            conn.connect((host,port))
        except:
            main.setText("No server available at specified host/port-address.","client.init")
            raise
        asynchat.async_chat.__init__(self,conn)
        self.set_terminator("\n")
        self.main=main
        self.buf=""

    def collect_incoming_data(self,data):
        self.buf+=data

    def found_terminator(self):
        self.main.setText(self.buf,"client.found_terminator")
        self.buf=""

    def sendMsg(self,text):
        self.push("Client push: "+text+"\n")

    def handle_close(self):
        self.close()
Benutzeravatar
jens
Moderator
Beiträge: 8461
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Dienstag 7. Februar 2006, 07:38

Ich kann dir leider keinen Tip geben zu deinen Problemen, aber auch du solltest dir mal [wiki]Lange Zeilen im Sourcecode[/wiki]ansehen :D

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Unzi
User
Beiträge: 5
Registriert: Montag 6. Februar 2006, 15:24
Wohnort: Erfurt, Thüringen
Kontaktdaten:

Samstag 11. Februar 2006, 22:44

Ich habe noch ein bisschen an dem Chat gewerkelt und alle Fehler bis auf den Separator berichtigt.
Das Ergebnis kann man hier herunterladen.
Ich wäre den Moderatoren sehr dankbar, wenn dieser Thread nach Showcase verschoben werden würde, da es sich nunmehr bei dem Programm um ein fertiges Projekt handelt.
Unzi
User
Beiträge: 5
Registriert: Montag 6. Februar 2006, 15:24
Wohnort: Erfurt, Thüringen
Kontaktdaten:

Sonntag 26. Februar 2006, 12:04

Unter der oben genannten Adresse ist nun die neue Version 1.5 erreichbar. Wer sich für die 1.0er interssiert, kann mir eine PN schicken.
Antworten