侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

python3+PyQt5 创建多线程网络应用-TCP客户端和TCP服务器实例

Python  /  管理员 发布于 7年前   185

本文在上文的基础上重新实现支持多线程的服务器。

以下为TCP客户端的程序代码:

#!/usr/bin/env python3import sysfrom PyQt5.QtCore import (QByteArray, QDataStream, QDate, QIODevice,    QRegExp, Qt)from PyQt5.QtWidgets import (QApplication, QDateEdit, QFrame, QGridLayout,    QHBoxLayout, QLabel, QLineEdit, QPushButton,    QWidget)from PyQt5.QtGui import QRegExpValidatorfrom PyQt5.QtNetwork import (QTcpSocket,)MAC = Truetry:  from PyQt5.QtGui import qt_mac_set_native_menubarexcept ImportError:  MAC = FalsePORT = 9407SIZEOF_UINT16 = 2class BuildingServicesClient(QWidget):  def __init__(self, parent=None):    super(BuildingServicesClient, self).__init__(parent)    self.socket = QTcpSocket()    self.nextBlockSize = 0    self.request = None    roomLabel = QLabel("&Room")    self.roomEdit = QLineEdit()    roomLabel.setBuddy(self.roomEdit)    regex = QRegExp(r"[0-9](?:0[1-9]|[12][0-9]|3[0-4])")    self.roomEdit.setValidator(QRegExpValidator(regex, self))    self.roomEdit.setAlignment(Qt.AlignRight|Qt.AlignVCenter)    dateLabel = QLabel("&Date")    self.dateEdit = QDateEdit()    dateLabel.setBuddy(self.dateEdit)    self.dateEdit.setAlignment(Qt.AlignRight|Qt.AlignVCenter)    self.dateEdit.setDate(QDate.currentDate().addDays(1))    self.dateEdit.setDisplayFormat("yyyy-MM-dd")    responseLabel = QLabel("Response")    self.responseLabel = QLabel()    self.responseLabel.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)    self.bookButton = QPushButton("&Book")    self.bookButton.setEnabled(False)    self.unBookButton = QPushButton("&Unbook")    self.unBookButton.setEnabled(False)    quitButton = QPushButton("&Quit")    if not MAC:      self.bookButton.setFocusPolicy(Qt.NoFocus)      self.unBookButton.setFocusPolicy(Qt.NoFocus)    buttonLayout = QHBoxLayout()    buttonLayout.addWidget(self.bookButton)    buttonLayout.addWidget(self.unBookButton)    buttonLayout.addStretch()    buttonLayout.addWidget(quitButton)    layout = QGridLayout()    layout.addWidget(roomLabel, 0, 0)    layout.addWidget(self.roomEdit, 0, 1)    layout.addWidget(dateLabel, 0, 2)    layout.addWidget(self.dateEdit, 0, 3)    layout.addWidget(responseLabel, 1, 0)    layout.addWidget(self.responseLabel, 1, 1, 1, 3)    layout.addLayout(buttonLayout, 2, 1, 1, 4)    self.setLayout(layout)    self.socket.connected.connect(self.sendRequest)    self.socket.readyRead.connect(self.readResponse)    self.socket.disconnected.connect(self.serverHasStopped)    #self.connect(self.socket,    #       SIGNAL("error(QAbstractSocket::SocketError)"),     #      self.serverHasError)    self.socket.error.connect(self.serverHasError)    self.roomEdit.textEdited.connect(self.updateUi)    self.dateEdit.dateChanged.connect(self.updateUi)    self.bookButton.clicked.connect(self.book)    self.unBookButton.clicked.connect(self.unBook)    quitButton.clicked.connect(self.close)    self.setWindowTitle("Building Services")  def updateUi(self):    enabled = False    if (self.roomEdit.text() and      self.dateEdit.date() > QDate.currentDate()):      enabled = True    if self.request is not None:      enabled = False    self.bookButton.setEnabled(enabled)    self.unBookButton.setEnabled(enabled)  def closeEvent(self, event):    self.socket.close()    event.accept()  def book(self):    self.issueRequest("BOOK", self.roomEdit.text(), self.dateEdit.date())  def unBook(self):    self.issueRequest("UNBOOK", self.roomEdit.text(), self.dateEdit.date())  def issueRequest(self, action, room, date):    self.request = QByteArray()    stream = QDataStream(self.request, QIODevice.WriteOnly)    stream.setVersion(QDataStream.Qt_5_7)    stream.writeUInt16(0)    stream.writeQString(action)    stream.writeQString(room)    stream << date    stream.device().seek(0)    stream.writeUInt16(self.request.size() - SIZEOF_UINT16)#overwrite seek(0)    self.updateUi()    if self.socket.isOpen():      self.socket.close()    self.responseLabel.setText("Connecting to server...")    self.socket.connectToHost("localhost", PORT)  def sendRequest(self):    self.responseLabel.setText("Sending request...")    self.nextBlockSize = 0    self.socket.write(self.request)    self.request = None  def readResponse(self):    stream = QDataStream(self.socket)    stream.setVersion(QDataStream.Qt_5_7)    while True:      if self.nextBlockSize == 0:        if self.socket.bytesAvailable() < SIZEOF_UINT16:          break        self.nextBlockSize = stream.readUInt16()      if self.socket.bytesAvailable() < self.nextBlockSize:        break      action = ""      room = ""      date = QDate()      #stream >> action >> room      action=stream.readQString()      room=stream.readQString()      if action != "ERROR":        stream >> date      if action == "ERROR":        msg = "Error: {0}".format(room)      elif action == "BOOK":        msg = "Booked room {0} for {1}".format(room,date.toString(Qt.ISODate))      elif action == "UNBOOK":        msg = "Unbooked room {0} for {1}".format(room,date.toString(Qt.ISODate))      self.responseLabel.setText(msg)      self.updateUi()      self.nextBlockSize = 0  def serverHasStopped(self):    self.responseLabel.setText(        "Error: Connection closed by server")    self.socket.close()  def serverHasError(self, error):    self.responseLabel.setText("Error: {0}".format(self.socket.errorString()))    self.socket.close()app = QApplication(sys.argv)form = BuildingServicesClient()form.show()app.exec_()

以下为TCP服务端的程序代码:

#!/usr/bin/env python3import bisectimport collectionsimport sysfrom PyQt5.QtCore import (QByteArray, QDataStream, QDate, QReadWriteLock, QThread,QIODevice, Qt)from PyQt5.QtWidgets import (QApplication, QMessageBox, QPushButton)from PyQt5.QtNetwork import (QAbstractSocket,QHostAddress, QTcpServer, QTcpSocket)PORT = 9407SIZEOF_UINT16 = 2MAX_BOOKINGS_PER_DAY = 5# Key = date, value = list of room IDsBookings = collections.defaultdict(list)def printBookings():  for key in sorted(Bookings):    print(key, Bookings[key])  print()class Thread(QThread):  lock = QReadWriteLock()  def __init__(self, socketId, parent):    super(Thread, self).__init__(parent)    self.socketId = socketId  def run(self):    socket = QTcpSocket()    if not socket.setSocketDescriptor(self.socketId):      #self.emit(SIGNAL("error(int)"), socket.error())      self.error.connect(socket.error)      return    while socket.state() == QAbstractSocket.ConnectedState:      nextBlockSize = 0      stream = QDataStream(socket)      stream.setVersion(QDataStream.Qt_5_7)      if (socket.waitForReadyRead() and        socket.bytesAvailable() >= SIZEOF_UINT16):        nextBlockSize = stream.readUInt16()      else:        self.sendError(socket, "Cannot read client request")        return      if socket.bytesAvailable() < nextBlockSize:        if (not socket.waitForReadyRead(60000) or          socket.bytesAvailable() < nextBlockSize):          self.sendError(socket, "Cannot read client data")          return      action = ""      room = ""      date = QDate()      action=stream.readQString()      if action in ("BOOK", "UNBOOK"):        room=stream.readQString()        stream >> date        try:          Thread.lock.lockForRead()          bookings = Bookings.get(date.toPyDate())        finally:          Thread.lock.unlock()        uroom = str(room)      if action == "BOOK":        newlist = False        try:          Thread.lock.lockForRead()          if bookings is None:newlist = True        finally:          Thread.lock.unlock()        if newlist:          try:Thread.lock.lockForWrite()bookings = Bookings[date.toPyDate()]          finally:Thread.lock.unlock()        error = None        insert = False        try:          Thread.lock.lockForRead()          if len(bookings) < MAX_BOOKINGS_PER_DAY:if uroom in bookings:  error = "Cannot accept duplicate booking"else:  insert = True          else:error = "{0} is fully booked".format(date.toString(Qt.ISODate))        finally:          Thread.lock.unlock()        if insert:          try:Thread.lock.lockForWrite()bisect.insort(bookings, uroom)          finally:Thread.lock.unlock()          self.sendReply(socket, action, room, date)        else:          self.sendError(socket, error)      elif action == "UNBOOK":        error = None        remove = False        try:          Thread.lock.lockForRead()          if bookings is None or uroom not in bookings:error = "Cannot unbook nonexistent booking"          else:remove = True        finally:          Thread.lock.unlock()        if remove:          try:Thread.lock.lockForWrite()bookings.remove(uroom)          finally:Thread.lock.unlock()          self.sendReply(socket, action, room, date)        else:          self.sendError(socket, error)      else:        self.sendError(socket, "Unrecognized request")      socket.waitForDisconnected()      try:        Thread.lock.lockForRead()        printBookings()      finally:        Thread.lock.unlock()  def sendError(self, socket, msg):    reply = QByteArray()    stream = QDataStream(reply, QIODevice.WriteOnly)    stream.setVersion(QDataStream.Qt_5_7)    stream.writeUInt16(0)    stream.writeQString("ERROR")    stream.writeQString(msg)    stream.device().seek(0)    stream.writeUInt16(reply.size() - SIZEOF_UINT16)    socket.write(reply)  def sendReply(self, socket, action, room, date):    reply = QByteArray()    stream = QDataStream(reply, QIODevice.WriteOnly)    stream.setVersion(QDataStream.Qt_5_7)    stream.writeUInt16(0)    stream.writeQString(action)    stream.writeQString(room)    stream<<date    stream.device().seek(0)    stream.writeUInt16(reply.size() - SIZEOF_UINT16)    socket.write(reply)class TcpServer(QTcpServer):  def __init__(self, parent=None):    super(TcpServer, self).__init__(parent)  def incomingConnection(self, socketId):    thread = Thread(socketId, self)    #self.connect(thread, SIGNAL("finished()"),    #       thread, SLOT("deleteLater()"))    thread.finished.connect(thread.deleteLater)    thread.start()class BuildingServicesDlg(QPushButton):  def __init__(self, parent=None):    super(BuildingServicesDlg, self).__init__(        "&Close Server", parent)    self.setWindowFlags(Qt.WindowStaysOnTopHint)    self.loadBookings()    self.tcpServer = TcpServer(self)    if not self.tcpServer.listen(QHostAddress("0.0.0.0"), PORT):      QMessageBox.critical(self, "Building Services Server","Failed to start server: {0}".format(self.tcpServer.errorString()))      self.close()      return    self.clicked.connect(self.close)    font = self.font()    font.setPointSize(24)    self.setFont(font)    self.setWindowTitle("Building Services Server")  def loadBookings(self):    # Generate fake data    import random    today = QDate.currentDate()    for i in range(10):      date = today.addDays(random.randint(7, 60))      for j in range(random.randint(1, MAX_BOOKINGS_PER_DAY)):        # Rooms are 001..534 excl. 100, 200, ..., 500        floor = random.randint(0, 5)        room = random.randint(1, 34)        bookings = Bookings[date.toPyDate()]        if len(bookings) >= MAX_BOOKINGS_PER_DAY:          continue        bisect.insort(bookings, "{0:1d}{1:02d}".format(   floor, room))    printBookings()app = QApplication(sys.argv)form = BuildingServicesDlg()form.show()form.move(0, 0)app.exec_()

以上这篇python3+PyQt5 创建多线程网络应用-TCP客户端和TCP服务器实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。


  • 上一条:
    python3+PyQt5 数据库编程--增删改实例
    下一条:
    python 应用之Pycharm 新建模板默认添加编码格式-作者-时间等信息【推荐】
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客