【Python基础篇021】黏包现象丨udp的socket服务

news2025/7/7 8:46:27

🌠前言

基于udp的socket服务有什么特点?黏包现象是什么?又是如何产生的?udp和tcp哪种会有黏包现象?看完这篇文章相信你会有所收获。

目录

🌠一、基于udp的socket服务

🌠二、TCP中的黏包现象

🌠三、基于UDP协议实现的黏包

🌠四、黏包现象产生原因

☄️4.1、tcp协议的特点

☄️4.2、Nagle算法和面向流的通信特点

☄️4.3、tcp协议的拆包机制

☄️4.4、udp协议的特点

☄️4.5、总结黏包两种情况

☄️4.6、黏包现象的触发

🌠一、基于udp的socket服务

使用UDP协议需要注意几点:

①UDP是面向无连接的,客户端在于服务器通信前无须建立连接,且UDP协议不保证发出的消息是否被收到,是否有丢失。

②UDP的接收和发送信息使用recvfrom()与sendto()函数

写UDP时的关键点

udp的server不需要监听也不需要建立连接,在启动服务之后只能被动的等待客户端发送消息过来,与此同时客户端发送消息的同时还会自带地址信息,消息回复的同时不仅需要发送消息,还需要把自己的地址发送过去

一个最简单的实现udp的socket服务的例子

client.py

import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
ip_port = ('127.0.0.1',8080)    #要发送对象的ip地址

sk.sendto(b'hello',ip_port)
ret,addr = sk.recvfrom(1024)    #将自己的地址发送
print('服务端地址:',addr)    #结果:服务端地址: ('127.0.0.1', 8080)
print(ret.decode('utf-8'))

sk.close()

server.py

import socket
sk = socket.socket(type=socket.SOCK_DGRAM) #dategram
sk.bind(('127.0.0.1',8080))
msg,addr = sk.recvfrom(1024)
print('客户端地址:',addr)      #结果:客户端地址: ('127.0.0.1', 52256)
print(msg.decode('utf8'))
sk.sendto(b'bye',addr)
sk.close()

🌠二、TCP中的黏包现象

tcp_server.py

import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen()
conn,addr = sk.accept()

while 1:
    cmd = input('>>>')
    conn.send(cmd.encode('utf8'))
    ret = conn.recv(1024).decode('utf8','ignore')
    print(ret)

conn.close()
sk.close()

#接收的数据发生错乱,数据接收多了,或者没接收完
#黏包现象

tcp_client.py

import socket
import subprocess
sk = socket.socket()
sk.connect(('127.0.0.1',8080))

while 1:
    cmd = sk.recv(1024).decode('gbk')
    ret = subprocess.Popen(cmd,shell=True,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.PIPE)
    std_out = 'stdout :' + (ret.stdout.read()).decode('gbk')
    std_err = 'stderr :' + (ret.stderr.read()).decode('gbk')
    print(std_out)
    print(std_err)

    sk.send(std_out.encode('utf8'))
    sk.send(std_err.encode('utf8'))

sk.close()

🌠三、基于UDP协议实现的黏包

提前说明:TCP是会粘包,UDP永远不会粘包

udp_server.py

import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen()
conn,addr = sk.accept()

while 1:
    cmd = input('>>>')
    conn.send(cmd.encode('utf8'))
    ret = conn.recv(1024).decode('utf8','ignore')
    print(ret)

conn.close()
sk.close()

#接收的数据发生错乱,数据接收多了,或者没接收完
#黏包现象,但是在UDP中就不会发生黏包现象,因为UDP上一次的消息没发完就直接丢失了

udp_client.py

import socket
import subprocess
sk = socket.socket()
sk.connect(('127.0.0.1',8080))

while 1:
    cmd = sk.recv(1024).decode('gbk')
    ret = subprocess.Popen(cmd,shell=True,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.PIPE)
    std_out = 'stdout :' + (ret.stdout.read()).decode('gbk')
    std_err = 'stderr :' + (ret.stderr.read()).decode('gbk')
    print(std_out)
    print(std_err)

    sk.send(std_out.encode('utf8'))
    sk.send(std_err.encode('utf8'))

sk.close()

🌠四、黏包现象产生原因

☄️4.1、tcp协议的特点

是因为TCP协议是面向流的协议,在发送的数据传输的过程中还有缓存机制来避免数据丢失

因为在连续发送小数据的时候、以及接收大小不符的时候都容易出现黏包现象,本质还是因为我们在接收数据的时候不知道发送的数据的长短

☄️4.2、Nagle算法和面向流的通信特点

tcp协议内部有Nagle算法这个优化算法,

TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务。
收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。
这样,接收端,就难于分辨出来了,必须提供科学的拆包机制。 即面向流的通信是无消息保护边界的。 
对于空消息:tcp是基于数据流的,于是收发的消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住,而udp是基于数据报的,即便是你输入的是空内容(直接回车),也可以被发送,udp协议会帮你封装上消息头发送过去。 
可靠黏包的tcp协议:tcp的协议数据不会丢,没有收完包,下次接收,会继续上次继续接收,己端总是在收到ack时才会清除缓冲区内容。数据是可靠的,但是会粘包。

☄️4.3、tcp协议的拆包机制

当发送端缓冲区的长度大于网卡的MTU时,tcp会将这次发送的数据拆成几个数据包发送出去。 
MTU是Maximum Transmission Unit的缩写。意思是网络上传送的最大数据包。MTU的单位是字节。大部分网络设备的MTU都是1500。
如果本机的MTU比网关的MTU大,大的数据包就会被拆开来传送,这样会产生很多数据包碎片,增加丢包率,降低网络速度

☄️4.4、udp协议的特点

UDP传输的特点是快速,无时延,但传输时无序、无流量控制、不可靠

☄️4.5、总结黏包两种情况

  • 一种是因为发送数据包时,每次发送的包小,因为系统进行优化算法,就将两次的包放在一起发送,减少了资源的重复占用。多次发送会经历多次网络延迟,一起发送会减少网络延迟的次数。因此在发送小数据时会将两次数据一起发送,而客户端接收时,则会一并接收。#即出现多次send会出现黏包
  • 第二种是因为接收数据时,又多次接收,第一次接收的数据量小,导致数据还没接收完,就停下了,剩余的数据会缓存在内存中,然后等到下次接收时和下一波数据一起接收。

☄️4.6、黏包现象的触发

server.py


#在Windows高版本上长链接关闭,
# 但是服务端仍要接收消息,此时就会默认发送空消息
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen()

conn,addr = sk.accept()
ret1 = conn.recv(12)
print(ret1)
ret2 = conn.recv(12)
print(ret2)     #接收到了一个空消息
ret3 = conn.recv(12)
print(ret3)
conn.close()
sk.close()

#多个send小的数据连在一起,会发生黏包现象,是tcp协议内部的优化算法造成的
#连续使用了send

 client.py

import socket
sk = socket.socket()
sk.connect(('127.0.0.1',8080))

sk.send(b'hello')
sk.send(b'egg')


import time
time.sleep(5)
sk.close()

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/5407.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

保边滤波之引导滤波与领域转换滤波

(1)引导滤波 局部窗口内输出图像O和引导图像G成线性关系OiakGibk, ∀i∈Ωk 假设输出图像O和输入图像I之间的关系为OiIi−ni,噪声最小即最小化ni,即 每个像素点i包含于多个窗口Ωk,每个窗口都会得到一个a、b值&#…

RK3399平台开发系列讲解(I/O篇)Linux最大文件数的限制机制

平台内核版本安卓版本RK3399Linux4.4Android7.1🚀返回专栏总目录 文章目录 一、Linux最大文件数的限制机制1.1、申请fd过程分析1.2、申请file内核对象过程分析沉淀、分享、成长,让自己和他人都能有所收获!😄 📢在Linux上能打开多少个文件,有两种限制: 第一种:进程级…

十、组件(8)

本章概要 递归组件异步更新队列Teleport 10.11.2 递归组件 组件可以在自己的模板中递归调用自身,但这需要使用 name 选项为组件指定一个内部调用的名称。 当调用 Vue.createApp({}).component({})全局注册组件时,这个全局的 ID 会自动设置为该组件的n…

【云原生】Docker的基本使用方法与优势

🍬Docker的基本使用方法和优势🥙一、简介🥪二、优势🌮三、基本使用🥙一、简介 Docker是基于Go语言实现的开源应用容器引擎,通过对应用组件的封装、分发、部署、运行等生命周期的管理,使用户的应…

配置Mysql与注册登录模块

后端职责可以粗浅的理解为处理各种数据,那么处理数据就可以从下面几个方面考虑: 数据的来源 根据不同的数据来源,我们探究两个方面的内容: 数据的形式 数据的操作 当然,一通操作以后,各个…

操作系统:进程与线程大解析

一文就懂进程与线程一、进程/线程相关概念进程中断并发与并行并发并行线程线程分类多进程和多线程上下文进程上下文进程上下文切换的场景线程上下文扩展:协程线程与协程的区别:协程的优势:二、进程/线程区别与关系进程和线程的区别进程和线程…

【C/C++】你知道位段吗?段位?不,是位段!

本章重点 什么是位段? 位段的内存分配 位段的跨平台问题 位段的应用 上一篇文章我详细介绍了第一种自定义类型--结构体。本章节我们认识一下另外一种自定义类型-- 位段。因为讲解位段时需要用到一点结构体的知识,所以我直接把链接放到这里可按需直接…

Swagger

一、Swagger简介 1.1、前言 前后端分离 Vue SpringBoot 当前主流的前后端分离技术栈 后端时代 前端只用管理静态页面,如html,其余的交给后端,而后端通过模板引擎,如jsp进行管理 前后端分离时代 后端:后端控制层&…

jsp健身房会员管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 健身房会员管理系统 是一套完善的web设计系统,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql,…

S7-200SMART PLC模拟量应用及创建库文件的具体方法

S7-200SMART PLC模拟量应用及创建库文件的具体方法 具体使用方法可参考以下内容: 模拟量计算公式: OUT = (In_chx - In_RawMin) * (In_EuMax - InEuMin) / (In_RawMax -In_RawMin) + In_EuMin 其中: OUT:转换后的实际值; In_chx:模拟量采集值; In_RawMax:原始数据的最大…

小侃设计模式(九)-组合模式

1.概述 组合模式(Composite Pattern)又叫部分整体模式,它创建了对象组的树形结构,将对象组合成树状结构以表示“整体-部分”的层析关系,使用户对单个对象和组合对象具有一致的访问性,是结构型设计模式的一…

Windows下一键搭建MBP系统,支持多种版本任意选择,免费永久使用,多系统使用新方案

Windows下一键搭建MBP系统,支持多种版本任意选择,免费永久使用,多系统使用新方案。 安装起来相当的简单,简单到只需要执行一行命令即可完成。使得游戏和开发可以兼顾,并且不用花费数万米的可以使用MBP。不仅如此,经过各项专业的测试,还有接近于原生的MBP系统性能。 效…

WinHex(二)

目录 1.我们打开WinHex,点击打开磁盘按钮 2.不同的文件在WinHex中有不同的文件显示 3.WinHex简单使用 4.删除之前所创建的虚拟磁盘 1.我们打开WinHex,点击打开磁盘按钮 2.不同的文件在WinHex中有不同的文件显示 3.WinHex简单使用 4.删除之前所创建的虚拟…

Java—Double类型进行加减乘除出错(精度)问题

前言: 我们知道,计算机在计算数据过程中都要先把源代码翻译成二进制的机器码,然后再进行相关的运算。然而在转换的过程中,有些十进制数无法用一个有限的二进制数来表示,就是说转换的时候出现了精度的丢失问题&#xff…

模型部署遇到的问题

1.不是有效的Win32应用程序 更改项目中的配置类型: 从网上下载的工程,之前人家是用来封装成库(dll)的,改成exe就好了。 vs学习问题 关于打开程序时不是有效的Win32应用程序_Lay_Nobody的博客-CSDN博客_vs不是有效的wi…

Spring Boot开发之SpringSercurity(续)

Spring Boot开发之SpringSercurity 一、授权1、打开上次项目以及数据库2、有的页面不登录也能访问,比如首页、登录以及注册等,因此对于某些请求不需要登录则放行这些接口(1)修改MySercurityConfig(2)修改TestController类(3)点击运行,在没登录…

数据抓取工具有哪些-数据抓取工具免费推荐的有哪些

随着社会的进步,科技的发展。不管是企业还是个人都清楚地明白了数据的重要性。不仅可以让我们掌握一手资源,同时还能通过数据更清楚竞争对手。同时也告别了手动复制粘贴的痛苦。 企业人员 通过爬取动态网页数据分析客户行为拓展新业务,分析…

java毕业设计健民中医药方网设计(附源码、数据库)

项目运行 环境配置: Jdk1.8 Tomcat8.5 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: Springboot mybatis Maven Vue 等等组成,B/…

NC5 二叉树根节点到叶子节点的所有路径和

描述 给定一个二叉树的根节点root,该树的节点值都在数字0−9 之间,每一条从根节点到叶子节点的路径都可以用一个数字表示。 1.该题路径定义为从树的根结点开始往下一直到叶子结点所经过的结点 2.叶子节点是指没有子节点的节点 3.路径只能从父节点到子节点…

java命令中的options

1. Java命令概述 安装JDK时,会使用java -version查看JDK版本,并验证安装是否成功直接输入java,会给出java命令的使用说明 -options:可选,java命令的命令行选项,多个选项使用空格分隔class:要启…