使用Python语言通过PyQt5和socket实现UDP服务器
前言
最近做了一个小软件,记录一下相关内容。
已有条件
现在已有一个硬件设备作为客户端(暂称其为“电路”)。
基于SIM卡,电路可以通过UDP协议传输数据(程序已经内置在电路中),只需要修改配置文件(位于SD卡中,主要修改服务器端的IP和端口)即可。
需求
我面向的需求是这样的:我需要开发一个服务器端的程序,接收多个客户端发来的数据并开发可视化界面。
总结
从开发角度和技术角度来看,软件的基础和核心技术是使用UDP协议进行数据传输,并使用PyQt5和pyqtgraph做可视化界面(还用到了QThread和自定义的下拉复选框),开发过程中还涉及到了内网穿透和NATAPP。
理论基础:运输层
为使用UDP协议进行数据传输,我大致复习了一下计算机网络中的运输层。
功能
运输层实现两台主机中进程之间的通信,一个主机中的多个进程可以和另一台主机中的多个进程通信。
运输层实现上述功能的方案是端口(port)
两个主要协议
运输层有两个主要协议:
- 传输控制协议TCP(Transmission Control Protocol)
- 用户数据报协议UDP(User Datagram Protocol)
TCP
- TCP是面向连接的
- 应用进程在传输数据前必须先建立连接,数据传送结束后要释放连接
- TCP连接是点对点的
- 每一条TCP连接只能有两个端点
- TCP不提供广播或多播服务
- TCP提供可靠交付的服务
- 通过TCP连接传送的数据,无差错、不丢失、不重复,并且按序到达
- TCP面向字节流
- 虽然应用程序和TCP的交互是一次一个数据块(大小不等),但TCP把应用程序交下来的数据仅仅看成一连串的无结构的字节流。
- TCP不保证接收方应用程序所收到的数据块和发送方应用程序所发出的数据块具有对应大小
- TCP保证接收方应用程序收到的字节流必须和发送方应用程序发出的字节流完全一样,同时接收方应用程序必须有能力识别收到的字节流,把它还原成有意义的应用层数据
UDP
- UDP是无连接的
- 在传输数据前不需要先建立连接,主机在收到UDP报文后不需要给出任何确认
- UDP是面向报文的
- 发送方:UDP对应用层交下来的报文,不合并也不拆分,添加首部后就交付给IP层
- 接收方:UDP对IP层交上来的UDP用户数据包,在去除首部后就直接交付给应用层的进程
- UDP尽最大努力交付
- 不保证可靠交付
- UDP支持一对一、一对多、多对一和多对多的交互通信
Python中的UDP编程
Python中的UDP编程可以通过socket
来实现,下面是一个简单样例
服务器端
import socket
server_ip = '127.0.0.1'
server_port = 9999
# 建立套接字
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # socket.SOCK_DGRAM代表是UDP通信
# 绑定IP和端口
s.bind((server_ip, server_port))
print('Bind UDP Server on %s:%s' % (server_ip, server_port))
while True:
# 接收数据
data, addr = s.recvfrom(1024)
print(addr, "\t", data)
# 发送数据
s.sendto(b'Received:%s'%data, addr)
客户端
import socket
server_ip = '127.0.0.1'
server_port = 59955
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # socket.SOCK_DGRAM代表是UDP通信
for data in [b'Michael', b'Tracy', b'Sarah']:
# 发送数据
s.sendto(data, (server_ip, server_port))
# 接收数据
# print(s.recv(1024).decode('utf-8'))
s.close()
值得注意的问题:缓冲区机制
UDP通信时,两个主机都要建立一个socket。
我这里的情况是客户端会一直给服务器端发数据。
在服务器端我发现socket一旦建立(准确来讲是创建socket对象并绑定至本地端口),就会一直接收数据,而不是调用recvfrom等函数(这类函数用来接收数据)时才会接收。
估计这是缓冲区机制,UDP应该就是这么设计的。大概就是socket对象创建后,收到的内容就会放入缓冲区,如果调用了recvfrom等数据接收函数就从缓冲区中取出数据。
内网穿透
为什么要用内网穿透
先不讲内网穿透是什么,有兴趣的可以自己去查查,下面我大概讲讲我浅显的理解。
在开发服务器端程序的过程中,我用的是自己的电脑,连接的网络是手机热点(因为在宿舍),因此我的电脑是没有公网IP的。
客户端程序用的是SIM卡,用的是公网(外网)IP,我开发的服务器端程序用的是私网(内网)IP。
公网IP是无法访问私网IP的(因为NAT),所以我需要让我的服务器端程序能够被外网访问。
问了一下@roadwide,他说要用内网穿透,并推荐了NATAPP等软件。
NATAPP的使用
怎么用呢?看看官方教程就知道了,链接放在文章末尾了。
讲一个比较关键的点,以理解下NATAPP是干嘛的
NATAPP运行起来后,就会将上图红框里的URL映射到本机(127.0.0.1)的80端口。
NATAPP会给我一个URL(作为我的外网IP),这样客户端程序通过访问NATAPP给我的URL就可以间接访问我在本机运行的服务器端程序。
PyQt5
QThread
服务器端程序的界面上有两个作用分别是开始接收数据和停止接收数据的按钮。
接收数据是通过一个while循环(循环体中接收一个数据)实现的,如果点击开始接收数据的按钮,那就运行while循环直到停止接收数据的按钮被点击。
刚开始实现数据接收功能时发现程序界面会崩溃、点击不动,因为直接把while循环写在软件主界面的代码中。
后来使用了PyQt5中的QThread(也有人说QThread并不是一个线程),在一个线程中实现while循环,然后就成功了。
在实现时我参考了其他网友的代码,参考链接放在文章末尾,注意一点是实现方式不止一种,比如说有些网友说用threading也可以,而且我也发现我的思路和参考的那份代码稍有不一样(我们实现的功能是相似的,但我只用了一个pyqtSignal,而那位网友用了两个)。
下拉复选框
这个软件需要有一个下拉复选框,而PyQt5中并没有这个东西,因此需要手动实现,这里我参考了其他网友的实现方式,参考链接见文章末尾。
参考链接
Python中的UDP编程
https://blog.csdn.net/vict_wang/article/details/81587093
https://www.jb51.net/article/165933.htm
理解NAT和内网穿透
https://baike.baidu.com/item/nat/320024
https://baike.baidu.com/item/内网穿透
NATAPP
https://natapp.cn/article/natapp_newbie
PyQt5
PyQt5下拉式复选框QComboCheckBox
QThread实现循环
https://segmentfault.com/a/1190000020746912?utm_source=tag-newest
AttributeError: 'PyQt5.QtCore.pyqtSignal' object has no attribute 'connect'
pyqtgraph
pyqtgraph中绘制多个线条(我实现这个功能时也看了pyqtgraph的example)
pyqtgraph中添加图例(legend)
作者:@臭咸鱼
转载请注明出处:https://www.cnblogs.com/chouxianyu/
欢迎讨论和交流!
使用Python语言通过PyQt5和socket实现UDP服务器的更多相关文章
- socket编程 ------ UDP服务器
void vLANcommunication( void *pvParameters ) { int32 listenfd; do{ listenfd = socket(AF_INET, SOCK_D ...
- google的python语言规范
Python语言规范 Lint Tip 对你的代码运行pylint 定义: pylint是一个在Python源代码中查找bug的工具. 对于C和C++这样的不那么动态的(译者注: 原文是less ...
- Python Web学习笔记之socket套接字
套接字是为特定网络协议(例如TCP/IP,ICMP/IP,UDP/IP等)套件对上的网络应用程序提供者提供当前可移植标准的对象.它们允许程序接受并进行连接,如发送和接受数据.为了建立通信通道,网络通信 ...
- python 网络编程 TCP/IP socket UDP
TCP/IP简介 虽然大家现在对互联网很熟悉,但是计算机网络的出现比互联网要早很多. 计算机为了联网,就必须规定通信协议,早期的计算机网络,都是由各厂商自己规定一套协议,IBM.Apple和Micro ...
- 部署基于python语言的WEB发布环境
一.部署说明 1.python语言介绍 python简介 2.实验环境 实验机器:Vmware虚拟机 8核10G 网卡:桥接模式 系统:centos7.5 防火墙:关闭 Selinux:关闭 网段:1 ...
- Python 语言规范
Python 语言规范 pychecker 对你的代码运行pychecker 定义: pychecker 是一个在Python 源代码中查找bug 的工具. 对于C 和C++这样的不那 么动态的( ...
- 【学习笔记】PYTHON语言程序设计(北理工 嵩天)
1 Python基本语法元素 1.1 程序设计基本方法 计算机发展历史上最重要的预测法则 摩尔定律:单位面积集成电路上可容纳晶体管数量约2年翻倍 cpu/gpu.内存.硬盘.电子产品价格等都遵 ...
- Python 语言规范(Google)
Python语言规范 Lint tip 对你的代码运行pylint 定义: pylint是一个在Python源代码中查找bug的工具. 对于C和C++这样的不那么动态的(译者注: 原文是less dy ...
- 关于《selenium2自动测试实战--基于Python语言》
关于本书的类型: 首先在我看来技术书分为两类,一类是“思想”,一类是“操作手册”. 对于思想类的书,一般作者有很多年经验积累,这类书需要细读与品位.高手读了会深有体会,豁然开朗.新手读了不止所云,甚至 ...
随机推荐
- (五)学习了解OrchardCore笔记——灵魂中间件ModularTenantContainerMiddleware的第一行②模块的功能部分
在(三)的时候已经说到模块集合用ForEachAsync的扩展方法分配多个任务,把每个modules的ManifestInfo分析出来的功能加入ConcurrentDictionary.我们先看看这个 ...
- JavaScript动画实例:旋转的正三角形
给定一个正三角形的重心坐标为(x0,y0),高为h,可以用如下的语句绘制一个底边水平的正三角形. ctx.beginPath(); ctx.moveTo(x0,y0-h*2/3); ctx.lineT ...
- 【一起学系列】之模板方法:写SSO我只要5分钟
意图 定义一个操作中的算法的骨架,将一些步骤延迟到子类中. Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤 模板方法模式的诞生 模板方法模式为我们提供了一 ...
- Oracle Database Tools
The following are some products, tools, and utilities you can use to achieve your goals as a databas ...
- P1092 虫食算(洛谷)
今天做了一道题,我之前吹牛的时候曾经说:“这个题我觉得深搜剪枝一下就可以了.”. 我觉得我之前说的没错“这个题深搜剪枝亿下,再加点玄学就可以了!” 题目描述 所谓虫食算,就是原先的算式中有一部分被虫子 ...
- Linux切换用户时报错/.bash_profile: Permission denied,命令行(终端提示符)出现-bash-4.2$
Linux切换用户时报错/.bash_profile: Permission denied,命令行(终端提示符)出现-bash-4.2$ 利用su - 切换用户时,发现有一个用户切时出现如下情况 [r ...
- web自动化 -- 消息提示框处理 (alert、confirm、prompt)
一.前提知识 1.警告消息框(alert) 警告消息框提供了一个"确定"按钮让用户关闭该消息框,并且该消息框是模式对话框,也就是说用户必须先关闭该消息框然后才能继续进行操作. 2. ...
- vue学习(十五) 过滤器简单实用
vue过滤器: 概念:vue.js允许你自定义过滤器可被用作一些常见文本的格式化.过滤器可以用在两个地方:插值表达式 v-bind表达式 由管道符指示 //过滤器调用时候的格式 {{ name ...
- Java基础之(IO流)
简介: 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作. 一.File ...
- 如何用redis做缓存
redis缓存 在互联网应用中经常需要用redis来缓存热点数据. redis数据在内存,可以保证数据读取的高效,接近每秒数十万次的吞吐量 减少下层持久层数据库读取压力,像mongodb,每秒近千次读 ...