UDP网络通信(发送端+接收端)实例 —— Python
简介
在网络通信编程中,用的最多的就是UDP和TCP通信了,原理这里就不分析了,网上介绍也很多,这里简单列举一下各自的优缺点和使用场景
| 通信方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| UDP | 及时性好,快速 | 视网络情况,存在丢包 | 与嵌入式设备通信,实时控制 场景 |
| TCP | 丢包会自动重发,理论上不用担心丢包问题 | 延时相对大一些 | 通信可靠性场景,比如IoT设备 控制,状态同步 |
一、socket
我们要进行网络通信,那么就要用到socket,socket即网络套接字,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。
在 Python 中,使用socket 模块的函数 socket 就可以创建一个socket对象,socket()函数的参数分别有family, type, proto。
1.其中family参数是指协议域,又称为协议族(family),常用的协议族有,AF_INET、AF_INET6、...等等,AF_INET指ipv4,AF_INET6即为ipv6;
2.然后是type,type指定socket类型,有SOCK_STREAM(流式套接字,主要用于 TCP 协议)和SOCK_DGRAM(数据报套接字,主要用于 UDP 协议)等等;
3.proto就是指定的协议,常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议,但是type和proto不可以随意组合,当proto参数为0或者不填时,会自动选择type类型对应的默认协议。
二、UDP发送数据
首先我们要导入socket包
import socket
创建一个udp套接字,ipv4协议,使用SOCK_DGRAM参数,不填proto,就会默认自动选择udp协议;
# 1、创建一个UDP套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
然后我们把要接收数据的那一端的ip地址和端口号放在一个元组里准备好
# 2. 准备接收方的地址和端口,'127.0.0.1:12341'表示目的ip地址,12341表示目的端口号
dest_addr = ('127.0.0.1', 12341) # 注意这是一个元组,其中ip地址是字符串,端口号是数字
准备好后就可以使用sendto函数进行发送了,要注意,需要对字符串进行编码才可以发送
# 3. 发送数据到指定的ip和端口
udp_socket.sendto("Hello,I am a UDP socket.".encode('utf-8'), dest_addr)
发送完就可以关闭套接字了
# 4. 关闭套接字
udp_socket.close()
例程一:UDP server端,UDP数据接收
#!/usr/bin/python3
# -*- coding: utf-8 -*-"""
udp通信例程:udp server端,修改udp_addr元组里面的ip地址,即可实现与目标机器的通信,
此处以单机通信示例,ip为127.0.0.1,实际多机通信,此处应设置为目标客户端ip地址
"""from time import sleep
import socketdef main():# udp 通信地址,IP+端口号udp_addr = ('127.0.0.1', 9999)udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# 绑定端口udp_socket.bind(udp_addr)# 等待接收对方发送的数据while True:recv_data = udp_socket.recvfrom(1024) # 1024表示本次接收的最大字节数# 打印接收到的数据print("[From %s:%d]:%s" % (recv_data[1][0], recv_data[1][1], recv_data[0].decode("utf-8")))if __name__ == '__main__':print("当前版本: ", __version__)print("udp server ")main()
代码解析
1.socket函数中第二个参数就是通信类型,此处SOCK_DGRAM 就是指定使用UDP通信
2.服务端需要使用bind函数绑定端口,客户端不需要,因为客户端发送的时候已经带了端口参数
例程二:UDP client端,UDP数据发送
#!/usr/bin/python3
# -*- coding: utf-8 -*-"""
udp通信例程:udp client端,修改udp_addr元组里面的ip地址,即可实现与目标机器的通信,
此处以单机通信示例,ip为127.0.0.1,实际多机通信,此处应设置为目标服务端ip地址
"""from time import sleep
import socketdef main():# udp 通信地址,IP+端口号udp_addr = ('127.0.0.1', 9999)udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# 发送数据到指定的ip和端口,每隔1s发送一次,发送10次for i in range(10):udp_socket.sendto(("Hello,I am a UDP socket for: " + str(i)) .encode('utf-8'), udp_addr)print("send %d message" % i)sleep(1)# 5. 关闭套接字udp_socket.close()if __name__ == '__main__':print("当前版本: ", __version__)print("udp client ")main()
例程三:多线程实现UDP数据收发
#!/usr/bin/python3
# -*- coding: utf-8 -*-"""
python多线程通信
"""from time import sleep
import socket
import threading# 定义全局变量
t1_count = 0
t2_count = 0def udp_received_hundle(s):global t1_countprint("this is thread 1 running")while True:t1_count += 1print("thread 1 第 %s 次运行" % t1_count)recv_data = s.recvfrom(1024) # 1024表示本次接收的最大字节数# 打印接收到的数据print("[From %s:%d]:%s" % (recv_data[1][0], recv_data[1][1], recv_data[0].decode("utf-8")))def udp_send_hundle(s):global t2_countprint("this is thread 2 running")while True:t2_count += 1print("")print("thread 2 第 %s 次运行" % t2_count)s.sendto(("Hello,I am a UDP socket for: " + str(t2_count)).encode('utf-8'), udp_addr)print("send %d message" % t2_count)print("")sleep(1)if __name__ == '__main__':print("当前版本: ", __version__)# 初始化# udp 通信地址,IP+端口号udp_addr = ('127.0.0.1', 9999)udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# 绑定端口:udp_socket.bind(udp_addr)# 定义线程thread_list = []t1 = threading.Thread(target=udp_received_hundle, args=(udp_socket, ))thread_list.append(t1)t2 = threading.Thread(target=udp_send_hundle, args=(udp_socket, ))thread_list.append(t2)for t in thread_list:t.setDaemon(True)t.start()for t in thread_list:t.join()print("exit all task.")print('all process end.')
代码解析
这里用到了多线程,虽然python中的多线程是假的多线程,实际上是一个线程分时复用,这里我们不深究,如果平常用到也就几个小任务跑一跑,抄我这个作业就ok。
多线程实际上是从t.join()后才开始正式运行的,这里一定要注意,不能漏了这个函数。
udp的收发与上面的例程几乎是一样的。
代码运行效果如下
当前版本: 1.0.0
this is thread 1 running
thread 1 第 1 次运行
this is thread 2 runningthread 2 第 1 次运行
send 1 message[From 127.0.0.1:9999]:Hello,I am a UDP socket for: 1
thread 1 第 2 次运行thread 2 第 2 次运行
send 2 message[From 127.0.0.1:9999]:Hello,I am a UDP socket for: 2
thread 1 第 3 次运行thread 2 第 3 次运行
send 3 message[From 127.0.0.1:9999]:Hello,I am a UDP socket for: 3
thread 1 第 4 次运行thread 2 第 4 次运行
send 4 message[From 127.0.0.1:9999]:Hello,I am a UDP socket for: 4
thread 1 第 5 次运行thread 2 第 5 次运行
send 5 message
使用网络调试助手,测试程序
注意,如果不是在本机windows系统上运行python程序,在Ubuntu虚拟机或者其他局域网内的机器上运行,要把windows的防火墙关了!!!
然后我们让其每隔一秒发送一次,发送10次,发送成功

完整代码:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: Williamimport socket,timedef main():# 1、创建一个UDP套接字udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# 2. 准备接收方的地址和端口,'192.168.0.107'表示目的ip地址,8080表示目的端口号dest_addr = ('192.168.8.226', 12341) # 注意这是一个元组,其中ip地址是字符串,端口号是数字# 3. 发送数据到指定的ip和端口for i in range(10):udp_socket.sendto("Hello,I am a UDP socket.".encode('utf-8'), dest_addr)time.sleep(1)# 4. 关闭套接字udp_socket.close()if __name__ == '__main__':main()
三、UDP接收数据
在之前发送数据的时候,我们可以看到,其端口号是一直在变得,那么我们要接收数据,就需要知道其端口号是什么,所以我们要先固定一个端口号,使用bind函数
# 2. 绑定本地的相关信息,如果不绑定,则系统会随机分配一个端口号
local_addr = ('', 12344) # ip地址和端口号,ip一般不用写,表示本机的任何一个ip
udp_socket.bind(local_addr)
接收数据使用recvfrom函数,其参数为接收的最大数据长度
# 3. 等待接收对方发送的数据
recv_data = udp_socket.recvfrom(1024) # 1024表示本次接收的最大字节数
接收完后将其打印出来:
# 4、打印接收到的数据
print(recv_data)
运行,通过网络调试助手发送数据
可以看到,打印出来的信息是一个元组,第一项接收到的字符串,第二项也是一个元组,包含对方的IP地址和端口号
完整代码:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: Williamimport socket,timedef main():# 1、创建一个UDP套接字udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# 2. 绑定本地的相关信息,如果不绑定,则系统会随机分配一个端口号local_addr = ('', 12344) # ip地址和端口号,ip一般不用写,表示本机的任何一个ipudp_socket.bind(local_addr)# 3. 等待接收对方发送的数据recv_data = udp_socket.recvfrom(1024) # 1024表示本次接收的最大字节数# 4、打印接收到的数据print(recv_data)# 5. 关闭套接字udp_socket.close()if __name__ == '__main__':main()
四、UDP收发数据
实现这样一个功能,通过UDP发送10次消息,然后等待接收,将接收的数据及其来源打印出来:


完成代码:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: Williamimport socket,timedef main():# 1、创建一个UDP套接字udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# 2. 绑定本地的相关信息,如果不绑定,则系统会随机分配一个端口号udp_socket.bind(('', 12344))# 3. 发送数据到指定的ip和端口,每隔1s发送一次,发送10次for i in range(10):udp_socket.sendto("Hello,I am a UDP socket.".encode('utf-8'), ('192.168.8.226', 12341))time.sleep(1)# 4. 等待接收对方发送的数据while(True):recv_data = udp_socket.recvfrom(1024)# 打印接收到的数据print("[From %s:%d]:%s"%(recv_data[1][0],recv_data[1][1],recv_data[0].decode("utf-8")))# 5. 关闭套接字udp_socket.close()if __name__ == '__main__':main()
五、同时收发数据
现在实现这样一个功能,即运行程序,然后在控制台输入字符串发送出去,同时,还可以接收数据,我使用多线程来实现这个程序,不过要实现方便接收,我们在程序的开始,将IP地址和端口号打印出来,实现效果如下:


实现代码:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: Williamimport socket,time,threadingdef recv_thread(socket):# 等待接收对方发送的数据while(True):try:recv_data = socket.recvfrom(1024)# 打印接收到的数据print("[From %s:%d]:%s"%(recv_data[1][0],recv_data[1][1],recv_data[0].decode("utf-8")))except Exception:breakdef main():# 1、创建一个UDP套接字udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# 2、绑定本地的相关信息,如果不绑定,则系统会随机分配一个端口号udp_socket.bind(('', 12344))# 3、打印本机ip地址和端口号print("local ipaddr and port->",socket.gethostbyname(socket.gethostname())+":12344")# 4、创建一个线程,用来接收数据t = threading.Thread(target=recv_thread, args=(udp_socket,))t.start()# 5、等待输入数据,然后发送出去,直到输入的数据为'quit'while(True):print("please input a string.input 'quit' to quit.")send_data = input()if send_data == "quit":breakelse:udp_socket.sendto(send_data.encode('utf-8'), ("192.168.8.226",12341))# 6、关闭套接字udp_socket.close()def main1():# 1、创建一个UDP套接字udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# 2. 准备接收方的地址和端口,'192.168.0.107'表示目的ip地址,8080表示目的端口号dest_addr = ('192.168.8.226', 12341) # 注意这是一个元组,其中ip地址是字符串,端口号是数字# 3. 发送数据到指定的ip和端口for i in range(1):udp_socket.sendto("Hello,I am a UDP socket.".encode('utf-8'), dest_addr)time.sleep(1)# 4. 等待接收对方发送的数据recv_data = udp_socket.recvfrom(1024) # 1024表示本次接收的最大字节数# 5、打印接收到的数据print(recv_data)# 4. 关闭套接字udp_socket.close()if __name__ == '__main__':main()
结语
这里只是UDP的简单使用,给大家一个示例参考,在实际应用过程中,涉及到复杂数据通信,还需要使用通信协议,协议收发,解包等函数,另外数据缓存也很关键,尤其是大数据量的情况下,通常会用到队列相关知识,这一部分就留给大家自行研究吧,如果这篇文章对你有用,不妨点赞关注,你的支持是我最大的动力。
相关文章:
UDP网络通信(发送端+接收端)实例 —— Python
简介 在网络通信编程中,用的最多的就是UDP和TCP通信了,原理这里就不分析了,网上介绍也很多,这里简单列举一下各自的优缺点和使用场景 通信方式优点缺点适用场景UDP及时性好,快速视网络情况,存在丢包 与嵌入…...
从零开始实现大语言模型(五):缩放点积注意力机制
1. 前言 缩放点积注意力机制(scaled dot-product attention)是OpenAI的GPT系列大语言模型所使用的多头注意力机制(multi-head attention)的核心,其目标与前文所述简单自注意力机制完全相同,即输入向量序列 x 1 , x 2 , ⋯ , x n x_1, x_2, \cdots, x_n x...
PTA 7-15 希尔排序
本题目要求读入N个整数,采用希尔排序法进行排序,采用增量序列{5,3,1},输出完成增量5和增量3后的5子排序和3子排序结果。 输入格式: 输入不超过100的正整数N和N个整数(空格分隔)。 输出格式: …...
【密码学】分组密码的设计原则
分组密码设计的目标是在密钥控制下,从一个巨大的置换集合中高效地选取一个置换,用于加密给定的明文块。 一、混淆原则 混淆原则是密码学中一个至关重要的概念,由克劳德香农提出。混淆原则就是将密文、明文、密钥三者之间的统计关系和代数关系…...
深入解析【C++ list 容器】:高效数据管理的秘密武器
目录 1. list 的介绍及使用 1.1 list 的介绍 知识点: 小李的理解: 1.2 list 的使用 1.2.1 list 的构造 知识点: 小李的理解: 代码示例: 1.2.2 list 迭代器的使用 知识点: 小李的理解࿱…...
NFS服务器、autofs自动挂载综合实验
综合实验 现有主机 node01 和 node02,完成如下需求: 1、在 node01 主机上提供 DNS 和 WEB 服务 2、dns 服务提供本实验所有主机名解析 3、web服务提供 www.rhce.com 虚拟主机 4、该虚拟主机的documentroot目录在 /nfs/rhce 目录 5、该目录由 node02 主机…...
自动驾驶事故频发,安全痛点在哪里?
大数据产业创新服务媒体 ——聚焦数据 改变商业 近日,武汉城市留言板上出现了多条关于萝卜快跑的投诉,多名市民反映萝卜快跑出现无故停在马路中间、高架上占最左道低速行驶、转弯卡着不动等情况,导致早晚高峰时段出现拥堵。萝卜快跑是百度 A…...
SpringSecurity框架【认证】
目录 一. 快速入门 二. 认证 2.1 登陆校验流程 2.2 原理初探 2.3 解决问题 2.3.1 思路分析 2.3.2 准备工作 2.3.3 实现 2.3.3.1 数据库校验用户 2.3.3.2 密码加密存储 2.3.3.3 登录接口 2.3.3.4 认证过滤器 2.3.3.5 退出登录 Spring Security是Spring家族中的一个…...
python安全脚本开发简单思路
文章目录 为什么选择python作为安全脚本开发语言如何编写人生第一个安全脚本开发后续学习 为什么选择python作为安全脚本开发语言 易读性和易维护性:Python以其简洁的语法和清晰的代码结构著称,这使得它非常易于阅读和维护。在安全领域,代码…...
WPF学习(4) -- 数据模板
一、DataTemplate 在WPF(Windows Presentation Foundation)中,DataTemplate 用于定义数据的可视化呈现方式。它允许你自定义如何展示数据对象,从而实现更灵活和丰富的用户界面。DataTemplate 通常用于控件(如ListBox、…...
GuLi商城-商品服务-API-品牌管理-JSR303分组校验
注解:@Validated 实体类: package com.nanjing.gulimall.product.entity;import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.nanjing.common.valid.ListValue; import com.nanjing.common.valid.Updat…...
PyTorch DataLoader 学习
1. DataLoader的核心概念 DataLoader是PyTorch中一个重要的类,用于将数据集(dataset)和数据加载器(sampler)结合起来,以实现批量数据加载和处理。它可以高效地处理数据加载、多线程加载、批处理和数据增强…...
TCP传输控制协议二
TCP 是 TCP/IP 模型中的传输层一个最核心的协议,不仅如此,在整个 4 层模型中,它都是核心的协议,要不然模型怎么会叫做 TCP/IP 模型呢。 它向下使用网络层的 IP 协议,向上为 FTP、SMTP、POP3、SSH、Telnet、HTTP 等应用…...
【学习笔记】无人机(UAV)在3GPP系统中的增强支持(五)-同时支持无人机和eMBB用户数据传输的用例
引言 本文是3GPP TR 22.829 V17.1.0技术报告,专注于无人机(UAV)在3GPP系统中的增强支持。文章提出了多个无人机应用场景,分析了相应的能力要求,并建议了新的服务级别要求和关键性能指标(KPIs)。…...
使用F1C200S从零制作掌机之debian文件系统完善NES
一、模拟器源码 源码:https://files.cnblogs.com/files/twzy/arm-NES-linux-master.zip 二、文件系统 文件系统:debian bullseye 使用builtroot2018构建的文件系统,使用InfoNES模拟器存在bug,搞不定,所以放弃&…...
Vue 3 与 TypeScript:最佳实践详解
大家好,我是CodeQi! 很多人问我为什么要用TypeScript? 因为 Vue3 喜欢它! 开个玩笑... 在我们开始探索 Vue 3 和 TypeScript 最佳实践之前,让我们先打个比方。 如果你曾经尝试过在没有 GPS 的情况下开车到一个陌生的地方,你可能会知道那种迷失方向的感觉。 而 Typ…...
PyMysql error : Packet Sequence Number Wrong - got 1 expected 0
文章目录 错误一错误原因解决方案 错误二原因解决方案 我自己知道的,这类问题有两类原因,两种解决方案。 错误一 错误原因 pymysql的主进程启动的connect无法给子进程中使用,所以读取大批量数据时最后容易出现了此类问题。 解决方案 换成…...
MVC 生成验证码
在mvc 出现之前 生成验证码思路 在一个html页面上,生成一个验证码,在把这个页面嵌入到需要验证码的页面中。 JS生成验证码 <script type"text/javascript">jQuery(function ($) {/**生成一个随机数**/function randomNum(min, max) {…...
OSPF.综合实验
1、首先将各个网段基于172.16.0.0 16 进行划分 1.1、划分为4个大区域 172.16.0.0 18 172.16.64.0 18 172.16.128.0 18 172.16.192.0 18 四个网段 划分R4 划分area2 划分area3 划分area1 2、进行IP配置 如图使用配置指令进行配置 ip address x.x.x.x /x 并且将缺省路由…...
云计算【第一阶段(29)】远程访问及控制
一、ssh远程管理 1.1、ssh (secureshell)协议 是一种安全通道协议对通信数据进行了加密处理,用于远程管理功能SSH 协议对通信双方的数据传输进行了加密处理,其中包括用户登录时输入的用户口令,建立在应用层和传输层基础上的安全协议。SSH客…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...
