Eli Bendersky's website » Code sample – socket client based on Twisted with PyQt

Eli Bendersky's website » Code sample – socket client based on Twisted with PyQt

Code sample – socket client based on Twisted with PyQt

May 26th, 2011 at 5:28 am

In an earlier post, I discussed one way of combining blocking socket I/O with a GUI, by means of a separate thread in which the I/O runs. I’ve also mentioned that one alternative is using asynchronous I/O with callbacks integrated into the GUI event loop. Here I want to present some sample code for this alternative.

One of the first things Python programmers will think about then considering asynchronous I/O is Twisted, which is an event-driven networking library written in pure Python. Twisted is a huge library, and it’s quite a job to learn how to use it properly. Here I’ll demonstrate just enough to accomplish the task at hand – re-create the simple socket client from the previous post that works as part of a PyQt GUI.

The full code sample is available for download – socket_client_twisted_pyqt.zip. Here is the socket client class using Twisted:

import structfrom twisted.internet.protocol import Protocol, ClientFactory
from twisted.protocols.basic import IntNStringReceiverclass SocketClientProtocol(IntNStringReceiver):""" The protocol is based on twisted.protocols.basic
        IntNStringReceiver, with little-endian 32-bit
        length prefix.
    """structFormat = "<L"prefixLength = struct.calcsize(structFormat)def stringReceived(self, s):self.factory.got_msg(s)def connectionMade(self):self.factory.clientReady(self)class SocketClientFactory(ClientFactory):""" Created with callbacks for connection and receiving.
        send_msg can be used to send messages when connected.
    """protocol = SocketClientProtocoldef __init__(self,connect_success_callback,connect_fail_callback,recv_callback):self.connect_success_callback = connect_success_callbackself.connect_fail_callback = connect_fail_callbackself.recv_callback = recv_callbackself.client = Nonedef clientConnectionFailed(self, connector, reason):self.connect_fail_callback(reason)def clientReady(self, client):self.client = clientself.connect_success_callback()def got_msg(self, msg):self.recv_callback(msg)def send_msg(self, msg):if self.client:self.client.sendString(msg)

A couple of notes:

  • Since I want to re-create the same length-prefixed protocol from the previous post, the IntNStringReceiver protocol class from twisted.protocols.basic comes in handy – it’s designed especially for strings prefixed by integer length headers. In our case, the prefix is a 4-byte little-endian unsigned integer, which I specify with the structFormat and prefixLength attributes. In addition I implement a couple of callbacks of the IProtocol interface.
  • SocketClientFactory is a straightforward subclass of Twisted’s ClientFactory, implementing the callbacks we’re interested in here.

This is all quite simple. The bigger problem was finding how to interface Twisted with PyQt. Since Twisted and a typical GUI library are both event-loop based, to make them work together we should use a custom reactor. Unfortunately, due to licensing issues, Twisted doesn’t come with a reactor for PyQt pre-packaged, and it should be obtained separately. Even more unfortunately, the PyQt reactor (qt4reactor.py) doesn’t appear to have a single well-defined address on the web – several slightly different versions of it can be found floating online. In my code sample I’ve included a version of qt4reactor.py which I found to work for my needs.

So, back to the code. This is the implementation of the PyQt client GUI that uses Twisted. Similarly to the thread-based sample, it keeps drawing a nice circle animation to demonstrate it’s never blocked. The full code is in the zip archive, here is only the interesting part:

class SampleGUIClientWindow(QMainWindow):def __init__(self, reactor, parent=None):super(SampleGUIClientWindow, self).__init__(parent)self.reactor = reactorself.create_main_frame()self.create_client()self.create_timer()def create_main_frame(self):self.circle_widget = CircleWidget()self.doit_button = QPushButton('Do it!')self.doit_button.clicked.connect(self.on_doit)self.log_widget = LogWidget()hbox = QHBoxLayout()hbox.addWidget(self.circle_widget)hbox.addWidget(self.doit_button)hbox.addWidget(self.log_widget)main_frame = QWidget()main_frame.setLayout(hbox)self.setCentralWidget(main_frame)def create_timer(self):self.circle_timer = QTimer(self)self.circle_timer.timeout.connect(self.circle_widget.next)self.circle_timer.start(25)def create_client(self):self.client = SocketClientFactory(self.on_client_connect_success,self.on_client_connect_fail,self.on_client_receive)def on_doit(self):self.log('Connecting...')# When the connection is made, self.client calls the on_client_connect# callback.#self.connection = self.reactor.connectTCP(SERVER_HOST, SERVER_PORT, self.client)def on_client_connect_success(self):self.log('Connected to server. Sending...')self.client.send_msg('hello')def on_client_connect_fail(self, reason):# reason is a twisted.python.failure.Failure  objectself.log('Connection failed: %s' % reason.getErrorMessage())def on_client_receive(self, msg):self.log('Client reply: %s' % msg)self.log('Disconnecting...')self.connection.disconnect()def log(self, msg):timestamp = '[%010.3f]' % time.clock()self.log_widget.append(timestamp + ' ' + str(msg))def closeEvent(self, e):self.reactor.stop()#-------------------------------------------------------------------------------
if __name__ == "__main__":app = QApplication(sys.argv)try:import qt4reactorexcept ImportError:# Maybe qt4reactor is placed inside twisted.internet in site-packages?from twisted.internet import qt4reactorqt4reactor.install()from twisted.internet import reactormainwindow = SampleGUIClientWindow(reactor)mainwindow.show()reactor.run()

The most important part of this code is in the last section, where the Twisted reactor and PyQt application are set up. A few steps have to be performed in a careful order:

  • An QApplication is created
  • qt4reactor is imported and installed into Twisted
  • The main window is created
  • Finally, the singleton Twisted reactor (which is actually a qt4reactor, since that’s the one we’ve installed) is run

Note that there’s no app.exec_() here, contrary to what you’d expect from a PyQt program. Since both PyQt and Twisted are based on event loops (in app.exec_() and reactor.run(), respectively), one of them should drive the other. The Twisted way is to let the reactor drive (hence we only call reactor.run() here). Inside its implementation, qt4reactor takes care of running an event loop in a way that dispatches events to both Twisted and PyQt.

Some additional notes:

  • The PyQt main window no longer needs a timer to query results from the client thread. When SocketClientFactory is created in create_client, some methods are passed to it as callbacks. These callbacks will be invoked when interesting events happen.
  • Even though Twisted’s reactor is a global singleton object, it’s good practice to pass it around in the application, instead of importing it from Twisted in multiple places. Here, SampleGUIClientWindow accepts the reactor object in its constructor and uses it later.
  • Twisted’s reactor keeps running until explicitly stopped. The user of a GUI expects the program to exit then the GUI is closed, so I call reactor.stop() in the main window’s closeEvent.

This is it. Once set up, Twisted integrates quite nicely with PyQt. Since both the GUI framework and Twisted are based on the concept of an event loop with callbacks, this is a natural symbiosis.

A final note: I’m very far from being a Twisted expert. In fact, this is the first time I really use it, so may be doing things not in the most idiomatic or optimal way. If you can recommend a better way to implement some parts of this sample, I’ll be very happy to hear about it.

Related posts:

  1. Code sample – socket client thread in Python
  2. Sample using QScintilla with PyQt
  3. New-style signal-slot connection mechanism in PyQt
  4. Boost.Asio with Protocol Buffers code sample
  5. Passing extra arguments to PyQt slots
posted on 2013-01-09 12:02 lexus 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/lexus/archive/2013/01/09/2852630.html

Eli Bendersky's website » Code sample – socket client based on Twisted with PyQt相关推荐

  1. python -socket -client

    socket client 发起连接. 流程为: 创建接口 发起连接 创建接口参数同socket server相同 发起连接的函数为socket.connect(ip,port) 这个地方的ip与po ...

  2. iOS Socket Client 通讯

    iOS Socket Client 通讯 阅读 239 收藏 19 2017-03-29 原文链接:https://github.com/guangzhouxia/JTSocket iOS Socke ...

  3. 通信网数据流量压力测试软件,Socket Client Tester(压力测试工具)

    Socket Client Tester是一款实用的网络调试工具,设置连接参数及客户端数量之后即可快速调试,它可以快速实现H5网页和应用程序之间的互通.同时,此工具可以和其他的网络工具服务端进行通讯, ...

  4. Socket Client 长连接及心跳检测

    简介: 所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象.一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制.从所处的地位来讲,套接 ...

  5. oracle24550,ORA-24550 Signal Received Error From Client Based Application

    ORA-24550 Signal Received Error From Client Based Application [ID 1284564.1] 修改时间 01-JUL-2011 类型 PRO ...

  6. 介绍一个功能强大的 Visual Studio Code 扩展 - Rest Client,能部分替代 Postman

    笔者平日用 Visual Studio Code 进行全栈开发,有的时候需要用 Postman 进行 API 测试.最近发现了一个好用的 Visual Studio Code 扩展:Rest Clie ...

  7. java socket client_java socket client

    用tornado做了个socket server.无奈联调的人员对接不上. 于是撸出了以下demo import java.io.*; import java.net.*; public class ...

  8. TCP Socket Client 测试工具,并发测试

    TCP协议 Socket客户端测试程序 发送数据支持ASCII与16进制格式 可以模拟并发压力测试 创建终端,然后发送数据 工具下载

  9. 虚幻商城Simple UDP TCP Socket Client的使用方式

  10. 程序员练级攻略(2018)-陈皓-笔记整理

    程序员练级攻略(2018)     开篇词     入门篇         零基础启蒙         正式入门     修养篇         程序员修养     专业基础篇         编程语 ...

最新文章

  1. MongoDB之conf配置文件详解
  2. Tomcat通过Redis实现session共享的完整部署记录
  3. Python处理JSON数据
  4. DLL+ ActiveX控件+WEB页面调用例子
  5. 简单扩展shiro 实现NOT、AND、OR权限验证(支持复杂一点的表达式)
  6. C++编程【Visual Studio 2017 环境搭建教程】【附:软件安装包】
  7. SAP S/4HANA客户关系管理之变
  8. hql mysql查询语句,HQL查询语言的使用介绍
  9. Android中Json数据解析
  10. 前嗅ForeSpider教程:采集图片/视频/资源文件
  11. FineUI分组显示弹框最新的在最上边
  12. .7-Vue源码之AST(3)
  13. [转]国内优秀论坛之大汇集
  14. vagrant up default: Warning: Authentication failure. Retrying...的一些解决办法(转自myx的博客)
  15. 聚宽macd底背离_什么是MACD顶背离和底背离?
  16. C语言数组相似度比对,C语言实验报告:碱基相似度比较
  17. 【win11远程桌面访问--基于云端服务器(腾讯云为例)frp的内网穿透实现】
  18. 什么是CDN,CDN有什么作用?
  19. 销售凭证、客户主数据
  20. rails网站分享到朋友圈功能是怎么实现的

热门文章

  1. MSP430第三十二章:Comp_B
  2. CCF-分蛋糕-Java
  3. zabbix3.0 之短信报警配置
  4. 《自控力》——[美]Kelly McGonigal
  5. python备份cisco交换机_思科交换机备份与还原
  6. 十年微博与没落搜狐的社交求变
  7. 华为程序员频交 Linux 内核补丁遭质疑,管理员后续回应:承认贡献,但请不要琐碎提交
  8. SEP12.1.2现在支持自动卸载其他某些杀毒软件
  9. win7网络不显示共享计算机,Win7电脑已开启共享却找不到设备 局域网显示空白该怎么解决...
  10. win7访问局域网计算机提示凭据,win7系统访问局域网共享文件时提示输入网络凭据的解决方法?...