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客…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...
云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...
ubuntu22.04有线网络无法连接,图标也没了
今天突然无法有线网络无法连接任何设备,并且图标都没了 错误案例 往上一顿搜索,试了很多博客都不行,比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动,重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...
Python训练营-Day26-函数专题1:函数定义与参数
题目1:计算圆的面积 任务: 编写一个名为 calculate_circle_area 的函数,该函数接收圆的半径 radius 作为参数,并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求:函数接收一个位置参数 radi…...
加密通信 + 行为分析:运营商行业安全防御体系重构
在数字经济蓬勃发展的时代,运营商作为信息通信网络的核心枢纽,承载着海量用户数据与关键业务传输,其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级,传统安全防护体系逐渐暴露出局限性&a…...
深入浅出JavaScript中的ArrayBuffer:二进制数据的“瑞士军刀”
深入浅出JavaScript中的ArrayBuffer:二进制数据的“瑞士军刀” 在JavaScript中,我们经常需要处理文本、数组、对象等数据类型。但当我们需要处理文件上传、图像处理、网络通信等场景时,单纯依赖字符串或数组就显得力不从心了。这时ÿ…...
中科院1区顶刊|IF14+:多组学MR联合单细胞时空分析,锁定心血管代谢疾病的免疫治疗新靶点
中科院1区顶刊|IF14:多组学MR联合单细胞时空分析,锁定心血管代谢疾病的免疫治疗新靶点 当下,免疫与代谢性疾病的关联研究已成为生命科学领域的前沿热点。随着研究的深入,我们愈发清晰地认识到免疫系统与代谢系统之间存在着极为复…...
