Chatclient mit twisted

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
da_hui
User
Beiträge: 4
Registriert: Montag 23. Oktober 2006, 21:14

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:
dev
User
Beiträge: 49
Registriert: Montag 23. Januar 2006, 09:52
Kontaktdaten:

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
da_hui
User
Beiträge: 4
Registriert: Montag 23. Oktober 2006, 21:14

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'
dev
User
Beiträge: 49
Registriert: Montag 23. Januar 2006, 09:52
Kontaktdaten:

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
da_hui
User
Beiträge: 4
Registriert: Montag 23. Oktober 2006, 21:14

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.
da_hui
User
Beiträge: 4
Registriert: Montag 23. Oktober 2006, 21:14

hat niemand eine Ahnung :?: Was hab ich denn im obigen code falsch gemacht?
dev
User
Beiträge: 49
Registriert: Montag 23. Januar 2006, 09:52
Kontaktdaten:

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
spdy
User
Beiträge: 2
Registriert: Montag 23. Juli 2007, 02:31

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
spdy
User
Beiträge: 2
Registriert: Montag 23. Juli 2007, 02:31

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.
Antworten