Seite 1 von 1

Chatclient mit twisted

Verfasst: Montag 23. Oktober 2006, 21:42
von da_hui
Hi,

ich beschäftige mich jetzt schon seit einigen Wochen mit phython und bin dabei vor ein paar Tagen auf Twisted gestoßen. Nun möchte ich einen Chat basteln, wobei der Chatserver kein problem ist, dazu gibt es sogar ein Beispiel script auf der twisted homepage.
Und jetzt zu meiner Frage: wie realisiere ich den Client mit twisted?
Da twisted ja event-driven ist weiß ich nicht wie ich die Nachrichten an den Server schicken soll. Mit

Code: Alles auswählen

self.transport.write()
kann ich zwar aus der Protocol Classe Nachrichten senden nur finde ich keinen Weg das von außen aus B.z einem Click-Event aufzurufen.
Das geht zwar zimlich einfach mit dem Standard socked modul, aber das muss doch auch mit twisted möglich sein.

Ich hoffe ihr versteht was ich meine und könnt mir helfen :wink:

Re: Chatclient mit twisted

Verfasst: Mittwoch 25. Oktober 2006, 14:57
von dev
da_hui hat geschrieben: Und jetzt zu meiner Frage: wie realisiere ich den Client mit twisted?
Da twisted ja event-driven ist weiß ich nicht wie ich die Nachrichten an den Server schicken soll. Mit

Code: Alles auswählen

self.transport.write()
kann ich zwar aus der Protocol Classe Nachrichten senden nur finde ich keinen Weg das von außen aus B.z einem Click-Event aufzurufen.
Du mußt Deiner GUI-Klasse einen Hinweis auf die Protokoll-Klasse mitgeben.
Z.B. in deren

Code: Alles auswählen

def __init__(self, protocol):
    self.protocol = protocol
.

Dann kannst Du daraus mittels

Code: Alles auswählen

self.protocol.transport.write('hello')
das Versenden anwerfen.

Ggf. die Protokoll-Klasse auch um eine write Methode erweitern.

Ciao,
dev

Verfasst: Mittwoch 25. Oktober 2006, 21:46
von da_hui
Danke für die Antwort!
Leider will es bei mir so nicht klappen.

Ich krig immer diesen Fehler:

self.protocol.transport.write(self.t1.GetLineText(0))
AttributeError: 'NoneType' object has no attribute 'write'

Verfasst: Donnerstag 26. Oktober 2006, 14:25
von dev
da_hui hat geschrieben: self.protocol.transport.write(self.t1.GetLineText(0))
AttributeError: 'NoneType' object has no attribute 'write'
ohne Code von Dir wird das ein Gestochere im Nebel.

Ciao,
dev

Verfasst: Donnerstag 26. Oktober 2006, 21:27
von da_hui
ok also hier ist der code:

Code: Alles auswählen

#client

import socket, wx
from twisted.internet import wxreactor
wxreactor.install()
from twisted.internet import reactor, protocol
from twisted.protocols.basic import LineReceiver


class ChatProtocol(LineReceiver):

    def connectionMade(self):
        print ("Connected to %s." % self.transport.getPeer().host)
    
    def lineReceived(self, line):
        print (line + "\n")
       
class BasicClientFactory(protocol.ClientFactory):
    
    protocol = ChatProtocol
    
class client_frame(wx.Frame):
    
    def __init__(self, protocol):
        
        self.protocol = protocol
    
        self.s = socket.socket()
        self.host = socket.gethostname()
        self.port = 1025
        
        wx.Frame.__init__(self, None, title="Chat Client", size=(410, 335))
        
        self.panel = wx.Panel(self)
        
        send_button = wx.Button(self.panel, label= 'Send')
        con_button = wx.Button(self.panel, label= 'Connect')
        
        self.Bind(wx.EVT_BUTTON, self.connect, con_button)
        self.Bind(wx.EVT_BUTTON, self.send, send_button)
    
        talk_box = wx.TextCtrl(self.panel)
        self.t1 = talk_box
        contents = wx.TextCtrl(self.panel, style=wx.TE_MULTILINE | wx.HSCROLL)
        self.t2 = contents
        
        hbox = wx.BoxSizer()
        hbox.Add(talk_box, proportion=1, flag=wx.EXPAND)
        hbox.Add(send_button, proportion=0, flag=wx.LEFT, border=5)
        hbox.Add(con_button, proportion=0, flag=wx.LEFT, border=5)
        
        vbox = wx.BoxSizer(wx.VERTICAL)
        vbox.Add(hbox, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
        vbox.Add(contents, proportion=1, flag=wx.EXPAND | wx.LEFT | wx.LEFT | wx.LEFT, border=5)
        
        self.panel.SetSizer(vbox)

    def connect(self, evt):
    
        reactor.connectTCP(self.host, self.port, BasicClientFactory())
        reactor.run()

    def send(self, evt):
        self.protocol.transport.write(self.t1.GetLineText(0))
        self.t2.AppendText(self.t1.GetLineText(0) + "\n")
        self.t1.Clear()


class App(wx.App):
    
    def OnInit(self):
        proto = BasicClientFactory.protocol
        frame = client_frame(proto)
        self.SetTopWindow(frame)
        frame.Show(True)
        return True

app = App(redirect = True)
app.MainLoop()
ich denke ich hab's so umgesetzt wie du's beschrieben hast.

Verfasst: Dienstag 7. November 2006, 15:35
von da_hui
hat niemand eine Ahnung :?: Was hab ich denn im obigen code falsch gemacht?

Verfasst: Sonntag 12. November 2006, 12:15
von dev
da_hui hat geschrieben:hat niemand eine Ahnung :?: Was hab ich denn im obigen code falsch gemacht?
zum wx Teil kann ich mangels Erfahrung nichts sagen.

Da Du aber Deine BasicClientFactory() sowieso innerhalb Deines client_frame instanziierst, ist eine Übergabe beim client_frame __init__ Blödsinn. Ich ging da von einer anderen Herangehensweise aus.

Dann ist proto = BasicClientFactory.protocol eine Zuweisung der Klasse, nicht eines instanziierten Objekts. [Ist das korrekt ausgedrückt?]

Dein ChatProtocol Objekt wird von der Factory erzeugt, wenn die socket Verbindung hergestellt wurde.

Um also in Deinem Modell zu bleiben, muß das ChatProtocol Objekt sich in der connectionMade Methode bei der der GUI Klasse melden.

Code: Alles auswählen

class ChatProtocol(LineReceiver):

    def connectionMade(self):
        print ("Connected to %s." % self.transport.getPeer().host)
        self.gui.protocol = self
 
Hilft Dir das weiter?

Ciao,
dev

Verfasst: Montag 23. Juli 2007, 02:36
von spdy
Auch wenns ein altes thema is fehlen dazu die guten Docus und ich hab im moment ungefair das selbe problem. Was ich persönlich nicht verstehe wie man twisted und wxpython über wxreactor zum miteinander reden bekommt.

so das man ordentlich daten von a nach b und b nach a verschieben kann.

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: UTF-8 -*-
import sys,time
from twisted.internet import wxreactor
if sys.modules.has_key('twisted.internet.reactor'):del sys.modules['twisted.internet.reactor']
wxreactor.install()
import wx
wx.SetDefaultPyEncoding("UTF-8") 
from twisted.words.protocols import irc
from twisted.internet import reactor
from twisted.internet import protocol
from twisted.python import threadable

        
class MainFrame(wx.Frame):

  def __init__(self):
    wx.Frame.__init__(self, None, -1, title="pyChat", size=(800,600))

    self.CreateStatusBar()
    self.MakeMenuBar()
    self.splitter = wx.SplitterWindow(self, -1, style=wx.SP_LIVE_UPDATE)
    self.splitter.SetMinimumPaneSize(125) #fix my position
    
    self.panel_left = wx.Panel(self.splitter, style=wx.SUNKEN_BORDER)
    self.panel_right = wx.Panel(self.splitter, style=wx.SUNKEN_BORDER)
    self.splitter.SplitVertically(self.panel_left, self.panel_right, sashPosition=125)
    
    self.tree = wx.TreeCtrl(self.panel_left, -1, style=wx.TR_HAS_BUTTONS|wx.TR_DEFAULT_STYLE|wx.SUNKEN_BORDER)
    self.workspace = wx.TextCtrl(self.panel_right, -1, "", style=wx.TE_MULTILINE|wx.TE_READONLY)
    self.chatbox = wx.TextCtrl(self.panel_right,-1,"",style = wx.TE_PROCESS_ENTER)
    self.__set_layout()
    
    self.chatbox.Bind(wx.EVT_TEXT_ENTER, self.ChatBox,)
    self.workspace.write(u"Welcome to PyChat Alpha\n")

  def __set_layout(self):
    self.splitter_sizer = wx.BoxSizer(wx.HORIZONTAL)
    self.splitter_sizer.Add(self.splitter, 1, wx.ALL|wx.EXPAND, 0)
    self.SetSizer(self.splitter_sizer)
    self.splitter_sizer.Fit(self)
    self.splitter_sizer.SetSizeHints(self)
    
    self.panel_left_sizer = wx.BoxSizer(wx.HORIZONTAL)
    self.panel_left_sizer.Add(self.tree, 1, wx.ALL|wx.EXPAND, 0) #tree window
    self.panel_left.SetSizer(self.panel_left_sizer)
    self.panel_left.Fit()
    
    self.panel_right_sizer = wx.BoxSizer(wx.VERTICAL)
    self.panel_right_sizer.Add(self.workspace, 1, wx.ALL|wx.EXPAND, 0) #main output
    self.panel_right_sizer.Add(self.chatbox,0,wx.ALIGN_BOTTOM|wx.EXPAND,0) #chatbox
    self.panel_right.SetSizer(self.panel_right_sizer)
    self.panel_right.Fit()
    
    self.SetAutoLayout(True)
    self.Layout()


  def MakeMenuBar(self):
    menu = wx.Menu()
    menu.Append(5000,"&Connect")
    menu.Append(5001,"&Disconnect")
    menu.Append(5002,"E&xit")
    menubar = wx.MenuBar()
    menubar.Append(menu,"&File")
    self.SetMenuBar(menubar)
    self.Bind(wx.EVT_MENU,self.OnConnect,id=5000)
    self.Bind(wx.EVT_MENU,self.OnDisconnect,id=5001)
    self.Bind(wx.EVT_MENU,self.OnExit,id=5002)

  def OnExit(self, evt):
    self.Close()

  def OnConnect(self,evt):
    firc = ConnectionFactory()
    reactor.connectTCP("localhost",6667,firc)

  def OnDisconnect(self,evt):
    reactor.stop() 

  def ChatBox(self,evt):
    unicodes = self.chatbox.GetValue()
    self.workspace.write(unicodes+"\n") #add to window
    self.chatbox.Clear()

class ircCore(irc.IRCClient):

  nickname = "changemeplz"
  channel = "#testchan"
   
  def connectionMade(self):
    irc.IRCClient.connectionMade(self) #call me once
    print "[connected at %s]" % time.asctime(time.localtime(time.time()))

  def signedOn(self):
    self.join(self.channel)

  def joined(self,channel):
    print "[joined %s]" % channel

class ConnectionFactory(protocol.ClientFactory):
    protocol = ircCore

    def clientConnectionLost(self,connector,reason):
        print "Connection Lost:",reason
        connector.connect()

    def clientConnectionFailed(self,connector,reason):
        print "Connection Failed:",reason
        reactor.stop()
   
class MyApp(wx.App):

  def OnInit(self):
    frame = MainFrame()
    frame.SetSize((800,600))
    frame.Show(True)
    return True

if __name__ == '__main__':
   app = MyApp()
   reactor.registerWxApp(app)
   reactor.run()
wenn jemand ahnung davon hat wo muss man etwas einfügen damit die kommunikation klappt is im moment ein wenig zu hoch für mich

Verfasst: Mittwoch 25. Juli 2007, 02:06
von spdy
konnte mein problem soweit lösen hab mir ne klasse erstellt
die die ganzen references zu den einzelnen klassen bei der erstellung bekommt

bin nun in der lage alles anzusteuern was ich brauche
was ich mich dabei nu frage ist dies eine gute oder schlechte idee.