python - wxPython 和高速公路 websockets

标签 python python-2.7 websocket twisted autobahn

我正在尝试基于 Python/Twisted/Autobahn.ws 为我的测试项目创建 GUI 应用程序。我正在关注那里的文章:wxPython and Twisted并尝试将我的应用程序连接到服务器。但是一开始我会得到一个错误:

Unhandled Error
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/twisted/python/log.py", line 88, in callWithLogger
    return callWithContext({"system": lp}, func, *args, **kw)
  File "/usr/local/lib/python2.7/dist-packages/twisted/python/log.py", line 73, in callWithContext
    return context.call({ILogContext: newCtx}, func, *args, **kw)
  File "/usr/local/lib/python2.7/dist-packages/twisted/python/context.py", line 118, in callWithContext
    return self.currentContext().callWithContext(ctx, func, *args, **kw)
  File "/usr/local/lib/python2.7/dist-packages/twisted/python/context.py", line 81, in callWithContext
    return func(*args,**kw)
--- <exception caught here> ---
  File "/usr/local/lib/python2.7/dist-packages/twisted/internet/_threadedselect.py", line 283, in _doReadOrWrite
    why = getattr(selectable, method)()
  File "/usr/local/lib/python2.7/dist-packages/twisted/internet/tcp.py", line 593, in doConnect
    self._connectDone()
  File "/usr/local/lib/python2.7/dist-packages/twisted/internet/tcp.py", line 607, in _connectDone
    self.protocol = self.connector.buildProtocol(self.getPeer())
  File "/usr/local/lib/python2.7/dist-packages/twisted/internet/base.py", line 1071, in buildProtocol
    return self.factory.buildProtocol(addr)
  File "/usr/local/lib/python2.7/dist-packages/twisted/protocols/policies.py", line 171, in buildProtocol
    return self.protocol(self, self.wrappedFactory.buildProtocol(addr))
  File "/usr/local/lib/python2.7/dist-packages/twisted/internet/protocol.py", line 123, in buildProtocol
    p = self.protocol()
exceptions.AttributeError: GUIClientProtocol instance has no __call__ method

我该如何解决这个问题?需要在我的类中定义 call 方法,或者我可能有更好的解决方案?

代码: 1) client_gui:

import wx
from twisted.internet import wxreactor
wxreactor.install()

from twisted.internet import reactor, ssl
from autobahn.twisted.websocket import WebSocketClientFactory, WebSocketClientProtocol, connectWS

from gui.filemanager import CloudStorage

class GUIClientProtocol(WebSocketClientProtocol):

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

if __name__ == '__main__':
    app = wx.App(False)
    frame = CloudStorage(None, -1, 'CloudStorage')
    frame.Show()

    host_url = "wss://%s:%s" % ("localhost", 9000)
    # create a WS server factory with our protocol
    factory = WebSocketClientFactory(host_url, debug = False)
    factory.protocol = GUIClientProtocol(frame)
    # SSL client context: using default
    if factory.isSecure:
        contextFactory = ssl.ClientContextFactory()
    else:
        contextFactory = None

    reactor.registerWxApp(app)
    connectWS(factory, contextFactory)
    reactor.run()

2) 服务器.py

import sys
import datetime
import pickle
from json import dumps, loads
from hashlib import sha256
from time import gmtime, strftime
from subprocess import Popen, PIPE, STDOUT

import sqlalchemy
import sqlalchemy.exc
from sqlalchemy import and_, func, asc
from sqlalchemy.orm import sessionmaker
from twisted.internet import reactor, ssl
from twisted.internet.task import deferLater
from twisted.python import log, logfile
from twisted.web.server import Site
from twisted.web.wsgi import WSGIResource
from autobahn.twisted.websocket import WebSocketServerFactory, WebSocketServerProtocol, listenWS

from balancer.balancer import Balancer
from db.tables import File as FileTable
from db.tables import Users, FileServer, FileSpace, Catalog
from flask_app import app
from utils import commands


log_file = logfile.LogFile("service.log", ".")
log.startLogging(log_file)
engine = sqlalchemy.create_engine('postgresql://user:password@localhost/csan', pool_size=20, max_overflow=0)


def checkServerStatus(ip, port):
    p = Popen(["python", "statuschecker.py", str(ip), str(port)], stdout=PIPE, stdin=PIPE, stderr=STDOUT)
    result = p.communicate()[0].replace('\n', '')
    return result.split('|')


class DFSServerProtocol(WebSocketServerProtocol):

    ... # ~450 lines of code 

if __name__ == '__main__':
    if len(sys.argv) > 1 and sys.argv[1] == 'debug':
        log.startLogging(sys.stdout)
        debug = True
        port = int(sys.argv[2])
    else:
        debug = False
        port = int(sys.argv[1])

    contextFactory = ssl.DefaultOpenSSLContextFactory('web/keys/server.key', 'web/keys/server.crt')

    server_addr = "wss://localhost:%d" % (port)
    factory = WebSocketServerFactory(server_addr, debug = debug, debugCodePaths = debug)
    factory.protocol = DFSServerProtocol
    factory.setProtocolOptions(allowHixie76 = True)

    listenWS(factory, contextFactory)

    # Flask with SSL under Twisted
    resource = WSGIResource(reactor, reactor.getThreadPool(), app)
    site = Site(resource)
    reactor.listenSSL(8080, site, contextFactory)
    # reactor.listenTCP(8080, web)
    reactor.run()

更新 #1: client_gui.py 看起来像这样:

import wx
from twisted.internet import wxreactor
wxreactor.install()

from twisted.internet import reactor, ssl
from autobahn.twisted.websocket import WebSocketClientFactory, WebSocketClientProtocol, connectWS

from gui.filemanager import CloudStorage

class GUIClientProtocol(WebSocketClientProtocol):

    def __init__(self):
        WebSocketClientProtocol.__init__(self)
        self.gui = None

    def connectionMade(self):
        self.gui = self.factory._frame
        self.gui.Show()

if __name__ == '__main__':
    app = wx.App(False)
    frame = CloudStorage(None, -1, 'CloudStorage')

    # create a WS server factory with our protocol
    host_url = "wss://%s:%s" % ("localhost", 9000)
    factory = WebSocketClientFactory(host_url)
    factory.protocol = GUIClientProtocol
    factory._frame = frame

    # SSL client context: using default
    if factory.isSecure:
        contextFactory = ssl.ClientContextFactory()
    else:
        contextFactory = None

    reactor.registerWxApp(app)
    connectWS(factory, contextFactory)
    reactor.run()

更新#2:
我的 CloudStorage 类的代码:

import wx
import os
import time

ID_BUTTON=100
ID_EXIT=200
ID_SPLITTER=300

class MyListCtrl(wx.ListCtrl):
    def __init__(self, parent, id):
        wx.ListCtrl.__init__(self, parent, id, style=wx.LC_REPORT)

        files = os.listdir('.')
        images = ['images/empty.png', 'images/folder.png', 'images/source_py.png',
        'images/image.png', 'images/pdf.png', 'images/up16.png']

        self.InsertColumn(0, 'Name')
        self.InsertColumn(1, 'Ext')
        self.InsertColumn(2, 'Size', wx.LIST_FORMAT_RIGHT)
        self.InsertColumn(3, 'Modified')

        self.SetColumnWidth(0, 220)
        self.SetColumnWidth(1, 70)
        self.SetColumnWidth(2, 100)
        self.SetColumnWidth(3, 420)

        self.il = wx.ImageList(16, 16)
        for i in images:
            self.il.Add(wx.Bitmap(i))
        self.SetImageList(self.il, wx.IMAGE_LIST_SMALL)

        j = 1
        self.InsertStringItem(0, '..')
        self.SetItemImage(0, 5)

        for i in files:
            (name, ext) = os.path.splitext(i)
            ex = ext[1:]
            size = os.path.getsize(i)
            sec = os.path.getmtime(i)
            self.InsertStringItem(j, name)
            self.SetStringItem(j, 1, ex)
            self.SetStringItem(j, 2, str(size) + ' B')
            self.SetStringItem(j, 3, time.strftime('%Y-%m-%d %H:%M',
        time.localtime(sec)))

            # if os.path.isdir(i):
            #     self.SetItemImage(j, 1)
            # elif ex == 'py':
            #     self.SetItemImage(j, 2)
            # elif ex == 'jpg':
            #     self.SetItemImage(j, 3)
            # elif ex == 'pdf':
            #     self.SetItemImage(j, 4)
            # else:
            #     self.SetItemImage(j, 0)

            if (j % 2) == 0:
                self.SetItemBackgroundColour(j, '#e6f1f5')
            j = j + 1

class CloudStorage(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, -1, title)

        self.splitter = wx.SplitterWindow(self, ID_SPLITTER, style=wx.SP_BORDER)
        self.splitter.SetMinimumPaneSize(50)

        p1 = MyListCtrl(self.splitter, -1)
        p2 = MyListCtrl(self.splitter, -1)
        self.splitter.SplitVertically(p1, p2)

        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_SPLITTER_DCLICK, self.OnDoubleClick, id=ID_SPLITTER)

        filemenu= wx.Menu()
        filemenu.Append(ID_EXIT,"E&xit"," Terminate the program")
        editmenu = wx.Menu()
        netmenu = wx.Menu()
        showmenu = wx.Menu()
        configmenu = wx.Menu()
        helpmenu = wx.Menu()

        menuBar = wx.MenuBar()
        menuBar.Append(filemenu,"&File")
        menuBar.Append(editmenu, "&Edit")
        menuBar.Append(netmenu, "&Net")
        menuBar.Append(showmenu, "&Show")
        menuBar.Append(configmenu, "&Config")
        menuBar.Append(helpmenu, "&Help")
        self.SetMenuBar(menuBar)
        self.Bind(wx.EVT_MENU, self.OnExit, id=ID_EXIT)

        tb = self.CreateToolBar( wx.TB_HORIZONTAL | wx.NO_BORDER |
        wx.TB_FLAT | wx.TB_TEXT)
        # tb.AddSimpleTool(10, wx.Bitmap('images/previous.png'), 'Previous')
        # tb.AddSimpleTool(20, wx.Bitmap('images/up.png'), 'Up one directory')
        # tb.AddSimpleTool(30, wx.Bitmap('images/home.png'), 'Home')
        # tb.AddSimpleTool(40, wx.Bitmap('images/refresh.png'), 'Refresh')
        # tb.AddSeparator()
        # tb.AddSimpleTool(50, wx.Bitmap('images/write.png'), 'Editor')
        # tb.AddSimpleTool(60, wx.Bitmap('images/terminal.png'), 'Terminal')
        # tb.AddSeparator()
        # tb.AddSimpleTool(70, wx.Bitmap('images/help.png'), 'Help')
        tb.Realize()

        self.sizer2 = wx.BoxSizer(wx.HORIZONTAL)

        button1 = wx.Button(self, ID_BUTTON + 1, "F3 View")
        button2 = wx.Button(self, ID_BUTTON + 2, "F4 Edit")
        button3 = wx.Button(self, ID_BUTTON + 3, "F5 Copy")
        button4 = wx.Button(self, ID_BUTTON + 4, "F6 Move")
        button5 = wx.Button(self, ID_BUTTON + 5, "F7 Mkdir")
        button6 = wx.Button(self, ID_BUTTON + 6, "F8 Delete")
        button7 = wx.Button(self, ID_BUTTON + 7, "F9 Rename")
        button8 = wx.Button(self, ID_EXIT, "F10 Quit")

        self.sizer2.Add(button1, 1, wx.EXPAND)
        self.sizer2.Add(button2, 1, wx.EXPAND)
        self.sizer2.Add(button3, 1, wx.EXPAND)
        self.sizer2.Add(button4, 1, wx.EXPAND)
        self.sizer2.Add(button5, 1, wx.EXPAND)
        self.sizer2.Add(button6, 1, wx.EXPAND)
        self.sizer2.Add(button7, 1, wx.EXPAND)
        self.sizer2.Add(button8, 1, wx.EXPAND)

        self.Bind(wx.EVT_BUTTON, self.OnExit, id=ID_EXIT)

        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.splitter,1,wx.EXPAND)
        self.sizer.Add(self.sizer2,0,wx.EXPAND)
        self.SetSizer(self.sizer)

        size = wx.DisplaySize()
        self.SetSize(size)

        self.sb = self.CreateStatusBar()
        self.sb.SetStatusText(os.getcwd())
        self.Center()
        self.Show(True)

    def OnExit(self,e):
        self.Close(True)

    def OnSize(self, event):
        size = self.GetSize()
        self.splitter.SetSashPosition(size.x / 2)
        self.sb.SetStatusText(os.getcwd())
        event.Skip()

    def OnDoubleClick(self, event):
        size =  self.GetSize()
        self.splitter.SetSashPosition(size.x / 2)

if __name__ == '__main__':
    app = wx.App(0)
    CloudStorage(None, -1, 'CloudStorage')
    app.MainLoop()

最佳答案

更新:我已经创建了一个完整的 example结合使用 wxPython 和 Autobahn 创建支持 WebSocket 的 UI。

问题是线路

factory.protocol = GUIClientProtocol(frame)

这会将 factory.protocol 设置为 GUIClientProtocol实例。但它必须是类。

现在,您显然希望从 GUIClientProtocol 中访问 frame。有(至少)两种选择。

选项 1:

factory.protocol = GUIClientProtocol
factory._frame = frame

然后从(正在运行的)协议(protocol)实例中作为 self.factory._frame 访问。

选项 2:实现 Factory.buildProtocol

关于python - wxPython 和高速公路 websockets,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24496312/

相关文章:

python - 如何在Python中用groupby语句填充na

Ubuntu 上的 Python 2.7

spring-boot - 没有 SockJS 的 Spring 启动 Websocket

java - 通过 SockJS 连接 Stomp 并订阅消息后仅接收 header

python - xlwings 调用一个应该创建文件的 python 函数,但没有创建文件

python - Simpy:分配新资源时同时释放资源

python - 获取 python 字符串中字符集的位置

python - 这段代码片段中 plt 指的是什么

node.js - 从纯js连接到socket.io

python - python 中如何验证用户输入是字母还是空格?