# Name: "Client4" : Client-Anwendung zur Didaktik der Socketprogrammierung # Autoren: Marco Schneider(Gymnasium Kusel) und Michael Schlemmer(Gymnasium am Rittersberg Kaiserslautern) # Datum: 03.10.2010 # Version: 4.2 # Python: 3.1 # -*- coding: utf-8 -*- # model import asyncore, socket class Model(asyncore.dispatcher): def __init__(self, cbVerb, cbGetr, cbEmpf): asyncore.dispatcher.__init__(self) self.buffer = b'' self.Ausgabe = '' self.cbVerb = cbVerb self.cbGetr = cbGetr self.cbEmpf = cbEmpf self.verbunden = False def handle_close(self): if self.verbunden: self.close() self.cbGetr() def handle_read(self): ausg=str(self.recv(4096),encoding='iso8859_15') if ausg != '': self.Ausgabe = ausg.replace("\r","") #Steuerzeichen "Carriage-Return" entfernen, da dieses als BOX in einer ASCII-Umgebung dargestellt würde. Diese Zeichen kommen nur in Folge einer unter Windows erzeugten ASCII-Datei vor, die an den Client zurückübermittelt wird. Z.B. bei Webseiten self.cbEmpf() def writable(self): return (len(self.buffer) > 0) def handle_write(self): sent = self.send(self.buffer) self.buffer = self.buffer[sent:] #pop buffer def cbVerb(self): pass def cbGetr(self): pass def cbEmpf(self): pass # view from tkinter import * class View(Tk): def __init__(self, cbVerbinde, cbSende, cbTrenne, cbHalt): Tk.__init__(self) # Callbacks self.cbVerbinde = cbVerbinde self.cbSende = cbSende self.cbTrenne = cbTrenne self.protocol("WM_DELETE_WINDOW",cbHalt) # cbHalt wird aufgerufen, wenn das 'X' gedrückt wird # Fenster self.title("Socket Client Version 4") self.geometry('687x609') # Labels self.lEmpfangen = Label(master=self, text="Verbindungsprotokoll", anchor=W, justify=LEFT) self.lEmpfangen.place(x=16, y=134, width=200, height=15) self.lAdresse = Label(master=self, text="Adresse", font=("Arial", 12), anchor=W, justify=LEFT) self.lAdresse.place(x=16, y=12, width=65, height=18) self.lremotePort = Label(master=self, text="Port", font=("Arial", 12), anchor=W, justify=LEFT) self.lremotePort.place(x=16, y=44, width=65, height=18) self.lzuSenden = Label(master=self, text="zu senden", anchor=W, justify=LEFT) self.lzuSenden.place(x=452, y=134, width=80, height=13) self.lMeldungen = Label(master=self, text="Meldungen", anchor=W, justify=LEFT) self.lMeldungen.place(x=16, y=486, width=80, height=15) self.lStatus = Label(master=self, text="", font=("Arial", 12, "bold"), fg="red", anchor=W, justify=LEFT) self.lStatus.place(x=210, y=72, width=100, height=25) # Entries self.eHost = Entry(master=self, background="white") self.eHost.place(x=88, y=8, width=121, height=21) self.eHost.insert(0,"www.hsg-kl.de") self.ePort = Entry(master=self, background="white") self.ePort.place(x=88, y=40, width=121, height=21) self.ePort.insert(0,"80") # Buttons self.bLoesche = Button(master=self, text="Ausgaben löschen", command=self.saeubern) self.bLoesche.place(x=523, y=104, width=150, height=25) self.bVerbinde = Button(master=self, text="Verbinden") self.bVerbinde.bind('',self.cbVerbinde) self.bVerbinde.place(x=88, y=72, width=105, height=25) self.bSende = Button(master=self, text="Senden") self.bSende.bind('',self.cbSende) self.bSende.place(x=210, y=104, width=220, height=25) self.bSende.config(state='disabled') self.bTrenne = Button(master=self, text="Trennen") self.bTrenne.bind('',self.cbTrenne) self.bTrenne.place(x=88, y=104, width=105, height=25) self.bTrenne.config(state='disabled') # Textwidgets und Scrollbars self.tSenden = Text(master=self, background="white") self.tSenden.place(x=452, y=152, width=206, height=329) self.tSenden.insert(END,'GET /abc.html HTTP1.1\n') self.tSenden.insert(END,'Host: www.hsg-kl.de\n') self.scrollbar1 = Scrollbar(master=self, orient=VERTICAL) self.tSenden.config(yscrollcommand=self.scrollbar1.set) self.scrollbar1.place(x=658, y=152, width=15, height=329) self.scrollbar1.config(command=self.tSenden.yview) self.tEmpfangen = Text(master=self, background="white") self.tEmpfangen.place(x=16, y=152, width=406, height=329) self.tEmpfangen.tag_config("senden", background="#FFDEAD") self.tEmpfangen.tag_config("getrennt", background="#FF3300") self.tEmpfangen.tag_config("empfangen", background="#ADD8E6") self.tEmpfangen.tag_config("aufgebaut", background="#7CFC00") self.tEmpfangen.tag_config(SEL, background="#FFD700") self.scrollbar2 = Scrollbar(master=self, orient=VERTICAL) self.tEmpfangen.config(yscrollcommand=self.scrollbar2.set) self.scrollbar2.place(x=422, y=152, width=15, height=329) self.scrollbar2.config(command=self.tEmpfangen.yview) self.tMeldungen = Text(master=self, background="white") self.tMeldungen.place(x=16, y=504, width=642, height=81) self.scrollbar3 = Scrollbar(master=self, orient=VERTICAL) self.tMeldungen.config(yscrollcommand=self.scrollbar3.set) self.scrollbar3.place(x=658, y=504, width=15, height=81) self.scrollbar3.config(command=self.tMeldungen.yview) # Timer starten self.after(0,self.poll) def poll(self): asyncore.poll(.1) self.after(1, self.poll) def saeubern(self): self.tEmpfangen.delete(1.0,END) self.tMeldungen.delete(1.0,END) # controller import time class Controller(object): def __init__(self): self.model = Model(self.verbunden, self.getrennt, self.ausgeben) self.view = View(self.verbinde, self.sende, self.trenne, self.Halt) self.ausloeser = True self.view.mainloop() def verbinde(self,event): if self.view.bVerbinde.cget( 'state' ) == 'active': self.model.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.model.connect((self.view.eHost.get(),int(self.view.ePort.get()))) self.verbunden() def verbunden(self): self.model.verbunden=True self.view.lStatus.config(text="verbunden") self.view.tEmpfangen.insert(END, '--- Socket-Verbindung aufgebaut ---\n', 'aufgebaut') self.view.tEmpfangen.see(END) self.view.bSende.config(state='active') self.view.bTrenne.config(state='active') self.view.bVerbinde.config(state='disabled') def sende(self,event): if self.view.bSende.cget( 'state' ) == 'active': text=self.view.tSenden.get("1.0",END) self.view.tEmpfangen.insert(END, text, 'senden') self.view.tEmpfangen.see(END) self.view.tSenden.delete(1.0,END) text=text.replace('\n','\r\n') # Carriage Return und Line Feed veranlassen das Absenden des Puffers self.model.buffer = bytes(text,encoding='iso8859_15') def trenne(self,event): self.ausloeser = False self.model.handle_close() self.model.verbunden=False def getrennt(self): self.view.lStatus.config(text="getrennt") if self.ausloeser: werwars = 'Server' else: werwars = 'Client' self.ausloeser = True self.view.tMeldungen.insert(END, "Verbindung wurde vom "+werwars+" um "+time.strftime("%H:%M:%S Uhr",time.localtime())+" getrennt.\n") self.view.tEmpfangen.insert(END, '--- Socket-Verbindung-getrennt ---\n', 'getrennt') self.view.tEmpfangen.see(END) self.view.bSende.config(state='disabled') self.view.bTrenne.config(state='disabled') self.view.bVerbinde.config(state='active') def ausgeben(self): self.view.tEmpfangen.insert(END, self.model.Ausgabe+'\n', 'empfangen') self.view.tEmpfangen.see(END) def Halt(self): # Aufräumarbeiten self.model.handle_close() # Schnittstelle schließen self.view.quit() # mainloop beenden self.view.destroy() # Fenster beseitigen # Hauptprogramm c = Controller()