pyqt5 qtextedit_《快速掌握PyQt5》第三十五章 网络应用

1bf99bb535d4fd29f7947c66f508bcde.png

PyQt5提供了QUdpSocket和QTcpSocket类分别用于实现UDP和TCP传输协议。这两个协议都可以用来创建网络客户端和服务端的应用程序。前者(UDP)以包的形式将数据从一台主机发送到另一台主机上。它只负责发送,但并不在乎是否发送成功。优点是轻巧快速;而后者(TCP)能够为应用程序提供可靠的通信连接,它以流的形式来发送数据,能够确保数据无差错地送达到其他计算机。优点是安全可靠。

TCP几乎已经是两个互联网程序通信的默认选择,但是UDP在某些方面还是有优势的(比如广播)。总之,具体情况还是要具体分析。在这一章我们就来了解下如果使用PyQt5所提供的相关网络模块来进行通信。

35.1 编写UDP客户/服务端代码

我们通过以下例子来了解下如何使用QUdpSocket——服务端程序不断发送系统时间给客户端,客户端接收数据并进行显示:

服务端

1a1db5ca0cb90f294ec013f30aee346e.png

客户端

93b755c2c8025c8d5d3e7455d753bd3a.png

以下是服务端代码:

import 

1. 实例化一个QUdpSocket对象;

2. 实例化QLabel和QPushButton控件并布局,按钮所连接的槽函数用来控制定时器QTimer的启动与停止。当定时器启动后,服务器每过一秒就会向客户端发送数据;

3. 实例化一个QTimer对象,并将timeout信号和槽函数连接起来。在槽函数中,笔者首先获取到当前的系统时间并存储到message变量中,然后将QLabel控件的值设为message显示在窗口中。接着调用encode()方法对message进行编码以用于传输。最后调用QUdpSocket对象的writedatagram()方法将编码后的字节数据发送到本地主机地址,目标端口为6666;

上述程序中用到的QHostAddress类通常与QTcpSocket, QTcpServer和QUdpSocket一起使用来连接主机或者搭建服务器。以下是我们可能会在程序中用到的一些地址:

28a497935fb04a096171f4e88a0c4640.png

运行截图如下:

08bae6ff979238330ee1aba5cc1153db.png

点击按钮后QLabel显示系统时间,同时该时间数据也不断被发送到客户端:

474cca477062b2a4fecde3a9d4cc8cc2.png

如果再按下按钮的话,时间停止更新,数据也会停止发送。

以下是客户端代码:

import 

1. 实例化QUdpSocket对象并调用bind()方法绑定地址和端口。每次可以准备读取新数据时,readyRead信号就会发射,我们在该信号所连接的槽函数中进行读取操作。首先调用hasPendingDatagrams()来判断是否还有要读取的数据,如果有的话就调用readDatagram()来读取数据,传入该方法的参数为要读取的数据大小,我们可以用pendingDatagramSize()方法获取。

readDatagram()一共返回三个值,分别是数据(字节),主机地址(QHostAddress对象)以及端口号(整型值)。之后我们用decode()将数据解码,用QHostAddress对象的toString()方法来获取到地址字符串。最后调用append()方法将message值显示在QTextBrowser控件上;

2. 实例化一个QTextBrowser文本浏览框对象并进行布局。

运行截图如下:

4673e01af3d3f0248b2ae3c021234be3.png

好,我们现在先在命令行窗口中运行服务端代码,并点击按钮开发发送数据:

d5aea40dd99cf41520c24e08c837cb51.png

2b0ab37ff45083da23030eb797c69638.png

接着再打开一个命令行窗口运行客户端代码,可以发现客户端显示了来自服务端程序的数据,地址以及使用的端口(该端口是系统随机分配的):

d329317214e5ad0b3294c6501f868492.png

c232ffec6b6d7a1a8b114d4fcec0575a.png

---

服务端和客户端程序如果都运行在一台主机上进行通信的话,我们也可以把它看成是进程间通信。如果要实现局域网通信(连接到同一网络下的两台主机),我们可以把服务端和客户端程序中的代码稍微修改下。

笔者现准备将服务端代码运行在另一台装有Windows系统的电脑上,而让客户端代码继续留在Mac电脑上运行。

首先需要获取下Mac电脑的内部IP地址,打开命令行窗口,输入ifconfig命令来查看(Linux上也是ifconfig,Windows上为ipconfig),可以看到地址为"192.168.1.102":

40adbe4a1884695a51532d2a30fdc912.png

接着我们需要将服务端代码中数据发送的目标地址修改为上方地址:

self

然后再将客户端代码中绑定的地址修改掉:

self

其余代码保持不变。现在先在命令行窗口中运行服务端代码:

b3b279b331886d3752fb73f68e675bc8.png

a5947f47d2159a6f6108e4c9d4595f4b.png

再运行客户端代码,发现通信成功:

3008a483030056a83031c42ad45b143a.png

1f1b64eda53eb29a24ff3b46e841fa79.png

​35.2 编写TCP客户/服务端代码

在这一节中我们来编写一个聊天程序——客户端向服务端发送聊天内容,服务端将接收到的数据通过api传给青云客智能机器人处理(当然大家也可以选择用小黄鸡SimSimi或者图灵机器人),获取到返回的数据后再发送给客户端:

服务端

e577a43cb65b0af953e355cdf22f2f62.png

客户端

86b61aad9a8d3f40d148ee2a2f053076.png

我们先来编写客户端代码:

import 

1. 实例化控件并完成界面布局,布局代码放在layout_init()函数中。如果大家忘了QSplitter控件的用法,可以去看下第二十四章;

2. 实例化一个QTcpSockset对象,并调用connectToHost()方法在指定端口上连接目标主机(此时会进行三次握手操作),如果客户端和服务端连接成功,则会发射connected()信号;

3. 在signal_init()函数中进行信号和槽连接的操作。当用户在文本编辑框QTextEdit中打完字后,点击发送按钮就可以将文本发送给服务端。在write_data_slot()槽函数中,我们首先获取文本编辑框中的文字,然后将它编码并用write()方法发送(不用再写目标地址和端口,因为之前已经用connectToHost()方法指定了),当然发送完后我们还有把文本编辑框清空掉。

4. 当用户点击关闭按钮后,调用close()方法关闭QTcpSocket套接字,当然窗口也得关掉。

5. 之前说过,当客户端和服务端连接成功的话,就会发射connected信号,我们将该信号连接到connected_slot()槽函数上,在该槽函数中我们只是简单的往屏幕上加了一行“Connected! Ready to chat! :)”文本来提示用户可以聊天了。

6. 跟QUdpSocket一样,当准备可以读取新数据时,readyRead信号就会发射。我们通过bytesAvailable()方法判断是否有数据,如果是的话则调用read()方法获取bytesAvailable()大小的数据。接着将数据解码并显示在屏幕上。

运行截图如下:

454764146f733fbd6883e113e8ef25e4.png

以下是服务端代码:

import 

1. 实例化一个QTextBrowser控件并进行布局;

2. 实例化一个QTcpServer对象,调用listen()方法对指定地址和端口进行监听。如果能够监听,则返回True,否则返回False。可以调用errorString()方法来获取监听失败的原因;

每当有来自客户端的新连接请求,QTcpServer就会发送newConnection信号。在与该信号连接的new_slot_socket()槽函数中,我们调用nextPendingConnection()方法来得到一个与客户端连接的QTcpSocket对象,并通过peerAddress()方法和peerPort()方法获取到客户端所在的主机地址和以及使用的端口;

3. 在与readyRead信号连接的read_data_slot()槽函数中,我们将来自客户端的数据解码,并作为参数传给get_answer()函数来获取青云客智能机器人的回答(关于requests库的使用方法,大家可以去看下它的文档,非常简单)。接着将answer编码后再调用write()方法发送数据给客户端;

4. 当连接关闭的话,就会发射disconnected信号。当客户端窗口关闭,那么与服务端的连接就会关闭,此时disconnected信号就会发射。在disconnected_slot槽函数中,我们在屏幕上显示失联客户端所在的主机地址和使用的端口。接着调用close()方法关闭套接字。

好我们现在先运行服务端代码:

34c00102f74021fd029fbcc1525de227.png

410f1a1c8df6f6d09e0d66e6e26f95f9.png

接着再打开一个命令行窗口运行客户端代码,客户端界面显示“Connected! Ready to chat! :)”文本:

181d341179b5142415aee153a202bd5a.png

服务端界面显示客户端所在主机的地址和使用的端口:

d4ae07b749070b3f4b35bc9716aaa560.png

通过客户端发送文本,并接收来自服务端的回答

3751caa58135fa8ccae76bd9318a47e0.png

我们还可以再打开一个命令行窗口来运行客户端代码(可以多开,这里就不再演示了)。

关闭客户端窗口,服务端界面显示失联客户端所在主机的地址和使用的端口:

fabab987ffe485ef53673c2eaba8b538.png

​35.3 小结

1. 编写基于UDP协议的客户端和服务端代码,我们只需要用到QUdpSocket即可。但如果是基于TCP协议的话,我们需要QTcpSocket和QTcpServer两个类来进行编写;

2. 如果想要建立安全的SSL/TLS连接,大家可以使用QSslSocket来代替QTcpSocket;

3. 笔者在这章只是对PyQt5的相关网络模块作了一个简单的使用介绍,也并没有讲解太多理论内容。如果想要更深入了解用Python进行网络编程的相关知识,大家可以去看下这本由Brandon Rhodes和John Goerzen共同编写的《Python网络编程》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值