Python网络编程之udp编程、黏包以及解决方案、tcpserver

这篇具有很好参考价值的文章主要介绍了Python网络编程之udp编程、黏包以及解决方案、tcpserver。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、UDP协议编程

Hello,大家好我是景天,上一章我们聊打了Python网络编程,详细介绍了基于TCP协议的编程。TCP协议,每次都要经过三次握手才能建立连接,效率比较低。有没有更快的数据传输方式呢?
今天我们就一起谈谈UDP。

1.udp协议发送数据

udp与tcp基本一样,就是协议类型改下即可
udp第一次只能客户端发送数据,服务端接收到后,知道了客户端的ip和端口,服务端才能给客户端发数据

(1)UDP协议 服务端

import socket 

# 1.创建udp对象
sk = socket.socket(type=socket.SOCK_DGRAM)

# 2.在网络中注册该主机(绑定ip和端口号)
sk.bind( ("127.0.0.1",9000) )

# 3.收发数据的逻辑
"""udp协议下,默认第一次只能接收数据(没有三次握手,不清楚对方的ip和端口号)"""
# 接受数据
msg , addr  = sk.recvfrom(1024)
print(msg.decode())
print(addr)

# 发送数据
sk.sendto( "我喜欢你个锤子".encode()  , addr )

# 4.关闭连接
sk.close()

(2)UDP协议 客户端

import socket 

# 1.创建udp对象
sk = socket.socket(type=socket.SOCK_DGRAM)

# 2.收发数据的逻辑
# 发送数据
msg = "你喜欢我么~"
# sendto(  二进制字节流 , ip端口号  )
sk.sendto(   msg.encode() ,  ("127.0.0.1",9000) )

# 接受数据
msg , addr = sk.recvfrom(1024)
print(msg.decode())
print(addr)

# 3.关闭连接
sk.close()

(3)服务端详解:

#导入模块
import socket

#1.创建socket对象,协议类型用 type关键字来标识。udp的类型是socket.SOCK_DGRAM
udp_server = socket.socket(type=socket.SOCK_DGRAM)
#2.绑定ip和端口
udp_server.bind((“127.0.0.1”,9020))
#3.收发数据,udp是无连接的协议,不需要建立三次握手。第一次只能接收数据
“”“udp协议下,默认第一次只能接收数据(没有三次握手,不清楚对方的ip和端口号)”“”
#接收数据
msg , addr = udp_server.recvfrom(1024)
print(msg.decode())
print(addr)

#在取到客户端的ip和端口号之后,可以发送数据
udp_server.sendto( “我喜欢你个锤子”.encode() , addr )

#4.关闭连接
udp_server.close()

(4)客户端详解

#导入模块
import socket
#1.创建udp——socket对象
udp_client = socket.socket(type=socket.SOCK_DGRAM)
#2.发收数据
msg = “你喜欢我么~”
#sendto( 二进制字节流 , ip端口号 )
udp_client.sendto( msg.encode() , (“127.0.0.1”,9020) )

#接受数据
msg , addr = udp_client.recvfrom(1024)
print(msg.decode())
print(addr)
#3.关闭连接
udp_client.close()

服务端打印:
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

客户端打印:
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

启用多个客户端:
可见,多个客户端都可以与服务端建立连接,不必等四次挥手断开连接。tcp服务端在与之前的客户端连接不断开的情况下,别人是无法连接上来的。upd可以
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

客户端打印
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

服务端默认先回复上次连接的客户端,input是个阻塞程序。服务端收到一个后,需要打字输入后,才能收到下一个客户端的消息
上一次发送消息是谁,服务端就把它的ip和端口号拿过来,回复过去

但凡涉及到聊天,聊天室,都采用udp协议
上传下载,保证数据不丢包采用tcp协议

2、tcp黏包

1.tcp协议在发送数据时,会出现黏包现象.

(1)数据粘包是因为在客户端/服务器的发送端和接收端都会有一个数据缓冲区,
缓冲区用来临时保存数据,默认空间都设置较大。在收发数据频繁时,由于tcp传输消息的无边界特点,不清楚应该截取多少长度,导致客户端/服务器端,都有可能把多条数据当成是一条数据进行截取,造成黏包

(2)发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一个数据包。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后在发送,这样接收方就收到了粘包数据。

(3)接收方引起的粘包是由于接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接缓冲区,用户进程从该缓冲区取数据,若下一个数据包到达时,上一个数据包尚未被用户进程取走,则系统可能把多条数据当成是一条数据进行截取

总结: TCP协议是面向连接的无边界协议

黏包现象一:
    在发送端,由于在缓冲区两个数据小,发送的时间隔短,TCP会根据优化算法把这些数据合成一个发送
    
黏包现象二:
    在接收端,由于在缓冲区没及时接受数据,截取数据时把多次发送的数据截取成一条,形成了黏包 

2.黏包对比:tcp和udp

#tcp协议:
缺点:接收时数据之间无边界,有可能粘合几条数据成一条数据,造成黏包
优点:不限制数据包的大小,稳定传输不丢包

#udp协议:
优点:接收时候数据之间有边界,传输速度快,不黏包
缺点:限制数据包的大小(受带宽路由器等因素影响),传输不稳定,可能丢包

#tcp和udp对于数据包来说都可以进行拆包和解包,理论上来讲,无论多大都能分次发送
但是tcp一旦发送失败,对方无响应(对方无回执),tcp可以选择再发,直到对应响应完毕为止
而udp一旦发送失败,是不会询问对方是否有响应的,如果数据量过大,易丢包

3.解决黏包问题

#解决黏包场景:
应用场景在实时通讯时,需要阅读此次发的消息是什么
#不需要解决黏包场景:
下载或者上传文件的时候,最后要把包都结合在一起,黏包无所谓.

模块 socketserver
#网络协议的最底层就是socket,基于原有socket模块,又封装了一层,就是socketserver
socketserver 为了实现tcp协议,server端的并发.

黏包现象:
(1)发送端,数据小,时间间隔短,造成黏包
(2)接收端,没有及时接受数据,可能把多次发送的数据当成一条截取.

案例。服务端分两次发型数据,发送的数据小,时间间隔较短。容易造成黏包。但是最新版的python3.11.2 多次发送时间短,也不会出现黏包
只有接收端,没有及时接收,才把多次发送的数据当成一条数据来接收
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

客户端收到时,如果接收不及时,会把两次发的,一次性收到打印出来,第二次接收没收到数据。第二次数据黏到第一次数据里面了
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

常规解决办法思路,多次发送数据时,加个时间间隔,但这种方法不可取,太耽误时间,影响程序运行速度
1.发送时,人为设置边界。第一步、先把要发送的数据大小发送过去。下面要发送的数据,都按这个长度截取。 第二步、发送真实的数据
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

接收时,第一步,先接受接下来要发送的数据的总大小 第二部,在接受真实的数据
可以解决黏包问题
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

但,我们每次发送的数据每次不一定一样,长度不一,不能能每次都去数

4.生产中,我们使用struct模块来解决黏包问题

struct 模块使用
基于 struct 模块–解决粘包问题的思路
先将真实的数据打包成固定长度的包;
先把固定长度的包发送过去;
接收后解包得到真实数据的长度;
接收真实数据

import struct

pack 打包
把任意长度数字转换成具有固定4个字节长度的字节流
unpack 解包
把4个字节长度的值恢复成原来的数字,返回元组

(1)pack

#i => int 要转换的当前类型是整型
pack()方法
pack()方法将任意长度的 数字 打包成新的数据,这个新数据的长度是固定。把任意长度数字转换成4个字节长度的字节流

pack()方法 第一个参数是数据格式,第二个参数是整数(数据的长度,转化成字节流后计算长度)
—返回值是一个新的字节流数据

使用pack长度也不是任意大,取值范围: -21亿~21亿左右 控制在1.8G之内 根据是int 32位机器的取值范围 2^31
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

MTU,链路层最大传输单元 最大1500
是包或帧的最大长度,一般以字节记。如果MTU过大,在碰到路由器时会被拒绝转发,因为它不能处理过大的包。
如果太小,因为协议一定要在包(或帧)上加上包头,那实际传送的数据量就会过小,这样也划不来。
大部分操作系统会提供给用户一个默认值,该值一般对用户是比较合适的。

res = struct.pack(“i” , 999999998)
print(res , len(res))

res = struct.pack(“i” , 1111111119)
print(res , len(res))

res = struct.pack(“i” , 3)
print(res , len(res))

res = struct.pack(“i” , 2000000000)
print(res , len(res))

把任意长度数据转换成4个字节长度的字节流。所以我们可以将数据打包,通过struct取其返回的长度,然后发送时按这个长度发送
struct.pack()返回的就是字节流,可以将任意长度的数据转换成4个字节长度的数据
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

(2)unpack

#i => 把对应的数据转化成整型
unpack()方法
unpack()方法将固定长度的 数字 解包成打包前数据真实的长度

unpack()方法 第一个参数是数据格式,第二个参数是 pack()方法打包后生成的新数据

返回值是一个元组,元祖中放着打包前数据真实的长度

tup = struct.unpack(“i” , res)
print(tup) #(2000000000,)
print(tup[0])
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

#解决黏包场景:
应用场景在实时通讯时,需要阅读此次发的消息是什么
#不需要解决黏包场景:
下载或者上传文件的时候,最后要把包都结合在一起,黏包无所谓.

这样,不论数据发送多长,struct都可以动态的取出其长度,打包成4个字节长度
接收时,先接收4个字节长度的数据,再接收真实数据。可以彻底解决黏包问题

服务端
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

客户端

python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

3、socketserver模块

#网络协议的最底层就是socket,基于原有socket模块,又封装了一层,就是socketserver
socketserver 为了实现tcp协议,server端的并发. 内部实现是多线程
使用时,需要继承该模块中的方法

也可以使用udp:
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

1.server配置

#网络协议的最底层就是socket,基于原有socket模块,又封装了一层,就是socketserver
socketserver 为了实现tcp协议,server端的并发. 内部实现是多线程

import socketserver

class MyServer(socketserver.BaseRequestHandler):
#该方法名是固定的,不能变.系统自动调用。里面我们可以自定义收发数据的逻辑
def handle(self):
print(self.request)
print(self.client_address)

#实例化socketserver里面的ThreadingTCPServer类 ( ip端口号 , 自定义的类 )
server = socketserver.ThreadingTCPServer((“127.0.0.1”,8898),MyServer)
#调用内部相关函数,服务器一直运行
server.serve_forever()

python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

继承父类,可以使用父类的构造方法
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

2.socketserver 与socket中的属性比较

self.request <=> conn tcp_server.accept()中的第一个返回值,新的套接字 等价 用来收发数据
self.client_address <=> addr (ip和端口)tcp_server.accept()中的第二个返回值
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

3.socketserver端口复用

#设置端口复用,更快释放端口
socketserver.TCPServer.allow_reuse_address = True
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

用了socketserver。服务端,只需要继承系统的类,不用自己创建socket对象。不用监听端口,端口复用,不用四次挥手,关闭套接字服务,这些都是继承的类完成
只需要实例化对象,绑定端口。
自己写收发逻辑即可
收发逻辑写在handle()方法里面,该方法继承了父类,方法名不能更改,系统自己调用
可以修改的点如下箭头指的地方:
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

客户端,服务端,收发数据必须交错,即是客户端要是先发,服务端就得先收。服务端先发,客户端就得先收
不能同时先收或先发

客户端发送
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

服务端接收
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

循环发收,以前通过socket,当服务端与客户端没有断开连接时,其他客户端不能再与服务端建立连接
现在通过socketserver可以实现,并发
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver

可以同时添加多个客户端,而且都能接收到服务端发来的消息
python udp 动态绑定,python快速入门,python,udp,网络编程,udp编程,黏包,tcpserver文章来源地址https://www.toymoban.com/news/detail-825778.html

到了这里,关于Python网络编程之udp编程、黏包以及解决方案、tcpserver的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 网络编程 p5 UDP编程

    基本介绍 类DatagramSocket和DatagramPacket实现了基于UDP协议网络程序。 UDP数据报通过数据报套接字DatagramSocket发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。 DatagramPacket对象封装了UDP数据报, 在数据报中包含了发送端的IP地址和端口号

    2024年02月16日
    浏览(37)
  • 【C++】6.网络编程:网络编程(TCP&UDP)

    网络编程是C++ API操作中很重要的一部分,包含 TCP 和 UDP 。 网络传输模型可以抽象为7个层: 物理层、数据链路层、网络层、传输层、会话层、表示层、应用层 。 但在使用TCP/IP协议时,可以简化为这4层: 网络接口、网络层、传输层、应用层 。 TCP:可靠传输,三次握手建立

    2024年02月16日
    浏览(43)
  • 【socket】从计算机网络基础到socket编程——Windows && Linux C语言 + Python实现(TCP+UDP)

    简单讲一下基础知识,便于后面代码的理解,建议大概浏览一下这一小节内容。这里讲的只是冰山一角,建议大家学习计算机网络相关知识,推荐几本书: 《计算机网络》(谢希仁) 《计算机网络 自顶向下方法》 《计算机网络技术》 《计算机网络基础及应用》 《Linux C从入

    2024年02月08日
    浏览(60)
  • 网络原理(三)—— UDP网络编程

    概念 :Socket 套接字,是由操作系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。基于Socket 套借字的网络程序开发就是网络编程。 通俗点来说,咱们程序员在写网络程序,其实主要编写的是应用层代码!(因为底层的哪些你动不了,也改变不了)也

    2024年01月19日
    浏览(45)
  • 网络编程 —— TCP 和 UDP 编程详解

    目录 网络编程主要函数介绍 1. socket 函数 2. bind 函数 3. listen 函数 4. accept 函数 5. connect 函数 6. send 函数 7. recv 函数 8. recvfrom 函数 9. sendto 函数 TCP 和 UDP 原理上的区别 TCP 编程 服务端代码: 客户端代码: UDP 编程 服务端代码: 客户端代码: 1. socket 函数 int socket(int domain, int

    2024年02月04日
    浏览(44)
  • UDP网络编程

    1.1、UDP——面向无连接(无连接,是因为UDP里有了对方的地址,直接发就好) 特点:           1、邮件系统服务模式的抽象           2、每个分组都携带完整的目的地址           3、不能保证分组的先后顺序           4、不进行分组出错的恢复和重传           5、不

    2024年02月12日
    浏览(40)
  • 网络编程 tcp udp http编程流程 网络基础知识

    OSI分层:应用层 表示层 会话层 传输层 网络层 数据链路层 物理层 tcp/ip: 应用层 传输层 网络层 数据链路 ip地址:唯一标识一台主机 ipv4 32位 ipv6 128位 寻址 可以反映物理上的一个变化 MAC地址:48 固化在计算机中 ip地址又两部分构成:网络号+主机号 端口号:标识一个应用程序

    2024年02月13日
    浏览(76)
  • 【网络编程】网络编程概念,socket套接字,基于UDP和TCP的网络编程

    前言: 大家好,我是 良辰丫 ,今天我们一起来学习网络编程,网络编程的基本概念,认识套接字,UDP与TCP编程.💞💞💞 🧑个人主页:良辰针不戳 📖所属专栏:javaEE初阶 🍎励志语句:生活也许会让我们遍体鳞伤,但最终这些伤口会成为我们一辈子的财富。 💦期待大家三连,关注

    2023年04月20日
    浏览(61)
  • JavaEE——网络编程(UDP套接字编程)

    概念: Socket 套接字就是操作系统给应用程序提供的网络编程 API。 我们可以认为 socket api 是和 传输层 密切相关的。 我们知道,在传输层中,提供了两个最核心的协议,UDP TCP。 因此,socket api 中也提供了两种风格。UDP TCP。 在这里我们简单认识一下 UDP 和 TCP : UDP : 无连接

    2024年02月13日
    浏览(61)
  • Qt - UDP网络编程

    UDP(User Datagram Protocol,用户数据报协议) UDP是一个轻量级、不可靠、面向数据报的、无连接的协议,多用于可靠性要求不严格,不是非常重要的传输。 QUdpSocket类继承自QAbstractSocket,用来发送和接收UDP数据报,”Socket”即套接字,套接字即IP地址+端口号。其中IP地址指定了网络

    2024年04月22日
    浏览(103)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包