首页 > 其他分享 >粘包

粘包

时间:2024-01-17 20:24:02浏览次数:30  
标签:socket send server json client msg 粘包

socket编程

  • socke编程又称套接字编程

TCP套接字编程模板

  • server 服务端
# 导入模块
import socket
# 获取服务端对象
server = socket.socket()
# 获取IP 和 端口号
IP='127.0.0.1'
PORT=9888
# 将IP和套接字绑定给对象
server.bind((IP,PORT))
# 监听
server.listen(5)
while True:
    # 接收
    conn,addr=server.accept()
    msg=conn.recv(1024)
    msg=msg.decode('utf-8')
    if msg=='q':
        conn.close()
        break
    print(msg)
    while  True:
        # 发送
        send_msg=input("请输入发送的信息:").strip()
        if len(send_msg)==0:
            continue
        conn.send(send_msg.encode('utf-8'))
        break
server.close()
  • client 客户端
# 导入模块
import socket
while True:
    # 获取客户端对象
    client=socket.socket()
    # 获取IP 和 端口号
    IP = '127.0.0.1'
    PORT = 9888
    # 绑定套接字
    client.connect((IP,PORT))
    # 发送信息
    send_msg=input("请输入想要发送的信息:").strip()
    if len(send_msg)==0:
        continue
    client.send(send_msg.encode('utf-8'))
    if send_msg=='q':
        client.close()
        break
    # 接收数据
    msg=client.recv(1024)
    print(msg.decode('utf-8'))

UDP套接字编程模板

  • client 客户端
# 导入模块
import socket
# 获取客户端对象
client=socket.socket(type=socket.SOCK_DGRAM)
# 获取IP和端口号
IP='127.0.0.1'
PORT=9881
# 绑定套接字
client.connect((IP,PORT))
send_msg='我是客户端'
client.sendto(send_msg.encode('utf-8'),(IP,PORT))

# 接收信息
msg,addr=client.recvfrom(1024)
print(msg.decode('utf-8'))
print(addr)
  • server 服务端
# 导入模块
import socket
# 获取服务端对象
server=socket.socket(type=socket.SOCK_DGRAM)
# 获取IP和端口号
IP='127.0.0.1'
PORT=9881
# 绑定套接字
server.bind((IP,PORT))
# 接收信息
msg,addr=server.recvfrom(1024)
print(msg.decode('utf-8'))
print(addr)
# 发送消息
send_msg='我是服务端'
server.sendto(send_msg.encode('utf-8'),addr)

粘包

(一)什么是粘包

  • 只有TCP有粘包的现象,UDP永远不会粘包

(1)socket收发消息的原理

  • socket收发消息的原理

img

  • 发送端可以是一K一K地发送数据,而接收端的应用程序可以两K两K地提走数据,当然也有可能一次提走3K或者6K数据,或者一次只提走几个字节的数据
    • 也就是说,应用程序所看到的数据是一个整体,或说是一个流,一条消息有多少字节对应用程序时不可见的
    • 因此TCP协议是面向流的协议,这也是容易出现粘包问题的原因
    • 而UDP是面向消息的协议,每个UDP段都是一条消息,应用程序必须以消息为单位提取数据,不能一次提取任意字节的数据,这一点和TCP是很不同的

(2)如何定义消息

  • 可以认为对方一次性write/send的数据为一个消息,需要明白的是当对方send一条信息的时候,无论底层怎样分段分片,TCP协议层会把构成整条消息的数据段排序完成后才呈现在内核缓冲区。
  • 例如基于tcp的套接字客户端往服务端上传文件,发送时文件内容是按照一段一段的字节流发送的,在接收方看了,根本不知道该文件的字节流从何处开始,在何处结束

所谓粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。

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

(3)TCP

  • TCP是面向连接的,面向流的,提供高可靠性服务
    • 收发两端(客户端和服务端)都要有一一成对的socket
    • 因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化算法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包
    • 这样,接收端,就难于分辨出来了,必须提供科学的拆包机制
      • 即面向流的通信时无消息保护边界的

(4)UDP

  • UDP是无连接的,面向消息的,提供高效率服务
    • 不会使用块的合并优化算法,, 由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息)
    • 这样,对于接收端来说,就容易进行区分处理了。 即面向消息的通信是有消息保护边界的。

(5)小结

  • tcp是基于数据流的,于是收发的消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住,而udp是基于数据报的,即便是你输入的是空内容(直接回车),那也不是空消息,udp协议会帮你封装上消息头,实验略
  • udp的recvfrom是阻塞的
    • 一个recvfrom(x)必须对唯一一个sendinto(y),收完了x个字节的数据就算完成,若是y>x数据就丢失,这意味着udp根本不会粘包,但是会丢数据,不可靠
  • tcp的协议数据不会丢,没有收完包,下次接收,会继续上次继续接收,己端总是在收到ack时才会清除缓冲区内容。数据是可靠的,但是会粘包。
  • 两种情况下会发生粘包。
    • 发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)

(二)什么是粘包问题

  • 客户端发送需要执行的代码
  • 服务端接收到客户端传过来的代码
    • 服务端调用方法执行代码并拿到执行后的结果
    • 服务端将执行后的结果进行返回
  • 客户端接收到服务端返回的结果并做打印输出

(1)server 服务端

# 导入模块
import socket
import subprocess
# 创建服务对象
server=socket.socket()
# 获取IP和端口号
IP='127.0.0.1'
PORT=9882
# 创建连接桥梁
server.bind((IP,PORT))
# 指定半连接池大小
server.listen(5)
# 接收数据和发送消息
while True:
    try:
        # 接收数据
        conn,addr=server.accept()
        # 得到的数据
        msg=conn.recv(1024)
        # 不允许传过来得数据位空
        if len(msg)==0:
            break
        # 接收客户端传过来得命令
        # 接收执行命令得结果
        msg_server=subprocess.Popen(msg.decode('utf-8'),
                                    shell=True,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE
                                    )
        # 返回命令得结果,成功或者失败
        true_msg=msg_server.stdout.read()
        false_msg=msg_server.stderr.read()
        # 反馈信息给客户端
        conn.send(true_msg)
        conn.send(false_msg)
    except Exception as e:
        break
conn.close()

(2)client 客户端

# 导入模块
import socket
import subprocess
# 创建服务对象
server=socket.socket()
# 获取IP和端口号
IP='127.0.0.1'
PORT=9882
# 创建连接桥梁
server.bind((IP,PORT))
# 指定半连接池大小
server.listen(5)
# 接收数据和发送消息
while True:
    try:
        # 接收数据
        conn,addr=server.accept()
        # 得到的数据
        msg=conn.recv(1024)
        # 不允许传过来得数据位空
        if len(msg)==0:
            break
        # 接收客户端传过来得命令
        # 接收执行命令得结果
        msg_server=subprocess.Popen(msg.decode('utf-8'),
                                    shell=True,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE
                                    )
        # 返回命令得结果,成功或者失败
        true_msg=msg_server.stdout.read()
        false_msg=msg_server.stderr.read()
        # 反馈信息给客户端
        conn.send(true_msg)
        conn.send(false_msg)
    except Exception as e:
        break
conn.close()

(3)问题引入

  • 服务端:
    • 执行代码,代码为空会报错
    • 执行代码,返回得数据肯操作空/报错信息
  • 客户端:
    • 输入得指令长度可能会超出范围
    • 接收到服务端得反馈结果可能会特别多
    • 如何打印超出数据范围(缓存到系统里)的数据

(4)粘包问题

  • 在 TCP 协议中是流式协议,数据是源源不断的传入到客户端中,但是客户端可以接受到的信息的长度是有限的
  • 当接收到指定长度的信息后,客户端进行打印输出
    • 剩余的其他数据会被缓存到 内存中
  • 当再次执行其他命令时
    • 新的数据的反馈结果,会叠加到上一次没有完全打印完全的信息的后面,造成数据的错乱
  • 当客户端想打印新的命令的数据时,打印的其实是上一次没有打印完的数据
    • 对数据造成的错乱

(5)粘包问题解决思路

  • 拿到数据的总大小 recv_total_size
  • recv_size = 0 ,循环接收,每接收一次,recv_size += 接收的长度
  • 直到 recv_size = recv_total_size 表示接受信息完毕,结束循环

(三)粘包存在问题

  • UDP协议不存在粘包问题,TCP协议存在粘包问题
  • 粘包问题出现的原因
    • TCP 协议是流式协议,数据像水流一样粘在一起,没有任何边界之分
    • 收数据没有接收干净,有残留,就会和下一次的结果混淆在一起
  • 解决粘包问题的核心法门就是
    • 每次都收干净
    • 不造成数据的混淆

(1)UDP协议不存在粘包问题

(1)服务端

from socket import *

server = socket(AF_INET, SOCK_DGRAM)

server.bind(('127.0.0.1', 8080))

res_from_client = server.recvfrom(1024)

print(res_from_client)
# (b'world', ('127.0.0.1', 56852))

res_from_client_two = server.recvfrom(1024)

print(res_from_client_two)
# (b'hello', ('127.0.0.1', 61798))

res_from_client_three = server.recvfrom(5)

print(res_from_client_three)
# OSError: [WinError 10040] 一个在数据报套接字上发送的消息大于内部消息缓冲区或其他一些网络限制,或该用户用于接收数据报的缓冲区比数据报小。
# 无法接收到 数据以外的数据 报错

(2)客户端

import socket
from socket import *

# 创建client对象
client = socket(AF_INET, SOCK_DGRAM)

client.connect(('127.0.0.1', 8080))

client.send(b'world')
client.send(b'hello')

msg_from_server = client.recvfrom(1024)
print(msg_from_server)

(3)小结

  • 当我们启动udp服务端后,由udp客户端向服务端发送两条数据
  • 但是在udp服务端只接收到了一条数据
  • 这是因为 udp 是报式协议,传送数据过程中会将数据打包直接发走,不会对数据进行拼接操作(没有Nagle算法)

(2)TCP协议存在粘包问题

(1)服务端

from socket import *

server = socket(AF_INET, SOCK_STREAM)

server.bind(('127.0.0.1', 8081))

server.listen(3)

conn, client_addr = server.accept()

msg_from_client = conn.recv(1024)
print(msg_from_client.decode('utf-8'))
# helloworld

conn.send(b'return')

conn.close()

(2)客户端

from socket import *

client = socket(AF_INET, SOCK_STREAM)

client.connect(('127.0.0.1', 8081))

client.send(b'hello')
client.send(b'world')

msg_from_server = client.recv(1024)
print(msg_from_server)
# b'return'

client.close()

(3)小结

  • 从以上我们可以看到
  • TCP协议传输过程中将我们的两次发送的数据拼接成了一个发送到服务端
  • 通过比较我们可知,udp协议虽然不存在粘包问题,但是,udp协议的安全性有待考量

(四)TCP协议解决粘包问题基础

(1)解决思路

  • 利用struct模块将传输过去的数据的总长度打包+到头部进行发送

(2)服务端

# 导入模块
import socket
import struct
import subprocess

# 获取服务端对象
server=socket.socket()
# 获取IP和端口号
IP='127.0.0.1'
PORT=9888
# 绑定给套接字-----建立连接
server.bind((IP,PORT))
# 指定半连接池大小
server.listen(5)
# 接收信息和发送信息
while True:
    # 从半连接池中取出连接请求,建立双向连接,拿出连接对象
    # 拿到连接对象和客户端的IP和端口号
    conn,addr=server.accept()
    while True:
        # 检测可能会抛出的异常,并对异常做处理
        try:
            # 基于取出来的连接对象,进行通信接收数据
            recv_msg=conn.recv(1024)
            if len(recv_msg)==0:
                break
            # 执行客户端传过来的命令
            # 接收执行命令的结果
            msg_server=subprocess.Popen(recv_msg.decode('utf-8'),
                                        shell=True,
                                        stdout=subprocess.PIPE,
                                        stderr=subprocess.PIPE
                                        )
            # 返回的命令结果----成功或者失败
            true_msg=msg_server.stdout.read()# 读取到成功的结果,二进制数据
            false_msg=msg_server.stderr.read()# 读取到失败的结果,二进制数据

            # 先发送头部消息(固定长度的bytes二进制数据:对数据信息的描述(包括数据的总长度))
            total_size_from_server=len(true_msg)+len(false_msg)
            # int 类型  ----固定长度的bytes
            # 参数i 表示整型
            total_size_from_server_pack=struct.pack('i',total_size_from_server)
            conn.send(total_size_from_server_pack)
            # 再将反馈信息发送给客户端
            conn.send(true_msg)
            conn.send(false_msg)
        except Exception as e:
            break
    conn.close()

(3)客户端

# 导入模块
import socket
# 解指定数据长度
import struct

# 创建客户端对象
client=socket.socket()
# 获取IP和端口号
IP='127.0.0.1'
PORT=9888
# 绑定套接字---创建客户端连接
client.connect((IP,PORT))
while True:
    msg=input("请输入想要发送的信息:").strip()
    # 输入的数据不能位空
    if len(msg)==0:
        continue
    # 发送的数据必须是二进制数据
    client.send(msg.encode('utf-8'))
    # 接收来自服务端返回的结果
    # 解决粘包问题
    # 1.先收到固定长度的头,将头部解析到数据的描述信息,拿到数据的总的大小
    # 解析出接收到的总数据的长度
    recv_total_size_msg=client.recv(4)
    # 解包返回的数据是元组,元组第一个参数就是打包的数字
    recv_total_size=struct.unpack('i',recv_total_size_msg)[0]
    # 2.recv_size=0,循环接收,没接收一次,recv_size+=接收查长度
    # 3.直到recv_siez=recv_total_size 表示接收信息完毕,结束循环
    # 初始化数据长度
    recv_size=0
    while recv_size<recv_total_size:
        # 接收的数据最多接收到1024字节的数据
        msg_from_server=client.recv(1024)
        # 本次接收到的打印的数据长度
        recv_size+=len(msg_from_server)

        # 对服务端接收到的信息继续解码
        msg_from_server=msg_from_server.decode('gbk')
        print(msg_from_server)
    else:
        print("命令结束!!")
    client.close()

(五)TCP协议解决粘包问题进阶

  • 通过json模式-----模板修改参数直接套用

  • server

# 导入模块
from  socket import *
# 将数据打包成4个长度的数据
import  struct
# 执行命令模块
import subprocess
# 将头部信息转换未json格式
import json


# 获取服务端对象
server=socket(AF_INET,SOCK_STREAM)
# 建立服务端连接
server.bind(('127.0.0.1',9698))
# 指定半连接池大小
server.listen(5)
# 接收消息  反馈信息
while True:
    # 接收
    conn,addr=server.accept()
    while True:
        # 检测可能会抛出的异常,并对异常进行处理
        try:
            # 接收信息
            msg=conn.recv(1024)
            # 不允许接收过来的信息为空
            if len(msg)==0:
                break

            # 执行命令
            # 接收执行命令的结果
            msg_server=subprocess.Popen(msg.decode('utf-8'),
                                        shell=True,
                                        stdout=subprocess.PIPE,
                                        stderr=subprocess.PIPE
                                        )
            # 获取接收的结果
            true_msg=msg_server.stdout.read()
            false_msg=msg_server.stderr.read()
            # 头部信息长度
            total_size=len(true_msg)+len(false_msg)

            # 自定义头部信息字典
            headers_dict={
                'total_size':total_size

            }
            # 将头部信息字典转为json字符串格式
            json_data=json.dumps(headers_dict)
            # 将json字符串转为二进制数据
            json_data_bytes=json_data.encode('utf-8')
            # 将json二进制数据打包
            json_size_pack=struct.pack('i',len(json_data_bytes))
            # 将打包数据发送出去
            conn.send(json_size_pack)
            # 将二进制数据发送出去
            conn.send(json_data_bytes)
            # 将执行命令得到的结果反馈给客户端
            conn.send(true_msg)
            conn.send(false_msg)
        except  Exception as  e:
            break
    conn.close()
  • client
# 导入模块
import json
import struct
from socket import *
# 导入解包模块
import subprocess
# 导入json模块

# 获取客户端对象
client=socket(AF_INET,SOCK_STREAM)
# 建立客户端连接
client.connect(('127.0.0.1',9698))
# 发送信息 接收信息
while True:
    send_msg=input("请输入你想发送的信息:").strip()
    # 发送信息不能为空
    if len(send_msg)==0:
        continue
    # 发送信息
    client.send(send_msg.encode('utf-8'))

    #接收信息
    # 接收服务端发来的打包数据
    json_data_pack=client.recv(4)
    # 将接收到的打包数据进行解包
    json_data_bytes_size=struct.unpack('i',json_data_pack)[0]
    # 接收二进制的头部json数据
    json_data_bytes=client.recv(json_data_bytes_size)
    # 将头部字典的二进制数据解码
    json_data=json_data_bytes.decode('utf-8')
    # 将解码后的json字符串进行反序列化 ----字典格式
    headers_dict=json.loads(json_data)
    # 取出头部数据的长度
    total_size1=headers_dict['total_size']
    # 定义一个数据大小
    recv_size=0
    # 循环打印出数据的内容
    while recv_size<total_size1:
        # 最多每次只能接收到1024个字节的数据
        msg=client.recv(1024)
        # 本次接收到的打印数据的长度
        recv_size+=len(msg)
        # 对接收的数据进行解码  gbk格式
        print(msg.decode('gbk'))
    else:
        print("命令结束!!!")
    client.close()

(补充)struct模块

  • struct.pack()
    

    是Python内置模块

    struct
    

    中的一个函数

    • 它的作用是将指定的数据按照指定的格式进行打包,并将打包后的结果转换成一个字节序列(byte string)
    • 可以用于在网络上传输或者储存于文件中。
  • struct.pack(fmt, v1, v2, ...)
    
    • 其中,fmt为格式字符串,指定了需要打包的数据的格式,后面的v1,v2,...则是需要打包的数据。
    • 这些数据会按照fmt的格式被编码成二进制的字节串,并返回这个字节串。
  • fmt
    

    的常用格式符如下:

    • x --- 填充字节
    • c --- char类型,占1字节
    • b --- signed char类型,占1字节
    • B --- unsigned char类型,占1字节
    • h --- short类型,占2字节
    • H --- unsigned short类型,占2字节
    • i --- int类型,占4字节
    • I --- unsigned int类型,占4字节
    • l --- long类型,占4字节(32位机器上)或者8字节(64位机器上)
    • L --- unsigned long类型,占4字节(32位机器上)或者8字节(64位机器上)
    • q --- long long类型,占8字节
    • Q --- unsigned long long类型,占8字节
    • f --- float类型,占4字节
    • d --- double类型,占8字节
    • s --- char[]类型,占指定字节个数,需要用数字指定长度
    • p --- char[]类型,跟s一样,但通常用来表示字符串
    • ? --- bool类型,占1字节
  • 具体的格式化规则可以在Python文档中查看(链接)。

img

import json
import struct

# 为了避免粘包,必须子定制报头
# 1T数据 文件路径 和 md5值
header = {
    'file_siez':111111111,
    'file_name':'/a/b/c/d/e/a.txt',
    'md5':'8f6fbf8347faa4924a76856701edb0f3'
}
# 为了将报头传输出去,需要将子定制的报头字典序列化未json字符串
header_str=json.dumps(header)
# 传输数据必须时二进制
header_str_bytes=header_str.encode('utf-8')

# 为了人客户端知道报头的长度,用struct模块将报头长度转换为4个字节
# 这4个字节只包含了一个数字,就是报头的长度
header_str_bytes_pack=struct.pack('i',len(header_str_bytes))

header_str_bytes_size=struct.unpack('i',header_str_bytes_pack)


print(f"原本的数据{header}")
# 原本的数据{'file_siez': 111111111, 'file_name': '/a/b/c/d/e/a.txt', 'md5': '8f6fbf8347faa4924a76856701edb0f3'}
print(f"json序列化数据{header_str}")
# json序列化数据{"file_siez": 111111111, "file_name": "/a/b/c/d/e/a.txt", "md5": "8f6fbf8347faa4924a76856701edb0f3"}
print(f"压缩后的数据{header_str_bytes_pack}")
# 压缩后的数据b'd\x00\x00\x00'
print(f"解包后的数据{header_str_bytes_size}")# (100,)

传输视频练习

  • server
# 导入socket 模块
import json
import  socket

# 导入struct模块 将数据打包成4个长度的数据
import  struct
# 导入json 模块将python对象转换为json字符串
# 导入os模 获取路径
import os

# 获取服务端对象
server=socket.socket()
# 建立服务端连接
server.bind(('127.0.0.1',9819))
# 指定半连接池大小
server.listen(5)
# 接收数据 和 反馈信息
while True:
    conn,addr=server.accept()
    while True:
        # 检查是否出现异常,并处理异常
        try:
            # 接收过来的视频名称
            file_name=conn.recv(1024)
            if not file_name:
                break
            file_name=file_name.decode('utf-8')
            # 获取视频的路径
            BASE_DIR=os.path.dirname(__file__)
            file_path=os.path.join(BASE_DIR,'video',file_name)
            # 读出数据
            with open(file_path,'rb') as f:
                data=f.read()
            # 获取报头长度
            header_size=len(data)
            # 自定义报头字典
            header_dict={
                'header_size':header_size
            }
            # 字典转为josn字符串
            json_data=json.dumps(header_dict)
            # 转为二进制
            json_data_bytes=json_data.encode('utf-8')
            # 打包
            json_data_bytes_pack=struct.pack('i',len(json_data_bytes))
            # 将打包好的数据反馈给客户端
            conn.send(json_data_bytes_pack)
            conn.send(json_data_bytes)
            conn.send(data)
        except Exception as  e:
            break
        conn.close()
  • client
# 导入socket模块
import socket
# 导入struct模块  解包
import struct
# 导入json模块  将json字符串转为python对象
import json
# 导入os模块,获取保存路径
import os
# 获取客户端对象
client=socket.socket()
# 建立客户端来南京
client.connect(('127.0.0.1',9819))
# 发送消息 和 接收反馈信息
while True:
    file_name=input("请输入发送的信息:").strip()
    if not file_name:
        continue
    client.send(file_name.encode('utf-8'))

     # 获取新的保存路径
    BASE_DIR=os.path.dirname(__file__)
    new_name=f'new_{file_name}'
    new_path=os.path.join(BASE_DIR,'video',new_name)

    # 接收数据
    json_data_bytes_pack=client.recv(4)
    # 解包
    json_data_bytes_size=struct.unpack('i',json_data_bytes_pack)[0]
    # 获取二进制json对象
    json_data_bytes=client.recv(json_data_bytes_size)
    # 解码
    json_data=json_data_bytes.decode('utf-8')
    # 获取python对象
    header_dict=json.loads(json_data)
    # 获取数据的大小
    header_size=header_dict['header_size']
    # 定义初始化数据长度
    recv_size=0
    # 定义初始化二进制变量
    while recv_size<header_size:
        data=client.recv(1024)
        recv_size+=len(data)
        with open(new_path, 'ab') as f:
            f.write(data)
    client.close()

标签:socket,send,server,json,client,msg,粘包
From: https://www.cnblogs.com/suyihang/p/17971082

相关文章

  • 网络编程之粘包问题
    粘包问题只有TCP有粘包现象,UDP永远不会粘包什么是粘包存在于客户端接收数据时,不能一次性收取全部缓冲区中的数据.当下一次再有数据来时,缓冲区中剩余的数据会和新的数据'粘连'在一起.这就是粘包现象。##什么是粘包?存在于TCP/IP协议中数据粘连在一起。##socket中造成粘......
  • 粘包问题
    粘包问题(1)粘包问题介绍粘包问题是在计算机网络中,特别是在使用面向流的传输协议(例如TCP)时经常遇到的一种情况。它主要涉及到数据在传输过程中的组织和接收问题。当使用TCP协议进行数据传输时,发送方往往会将要传输的数据切分成小的数据块,并通过网络发送给接收方。然而,底层的......
  • 粘包
    粘包【一】什么是粘包须知:只有TCP有粘包现象,UDP永远不会粘包【二】什么是粘包问题客户端发送需要执行的代码服务端接收到客户端传过来的代码服务端调用方法执行代码并拿到执行后的结果服务端将执行后的结果进行返回客户端接收到服务端返回的结果并做打印输出【1】......
  • 对解决粘包问题的理解
    【一】什么是粘包问题想象你正在通过一条很窄的管道(网络连接)发送一串珠子(数据包)。在管道的另一端,有人(接收方)正在接收这些珠子。为了让对方知道每串珠子的开始和结束,你决定在每串珠子之间放一小块纸条(数据包的边界标记)。但是,如果这些珠子和纸条在管道中相互挤压,可能会导致纸条丢......
  • TCP粘包/拆包,如何解决
    TCP粘包(TCPPacketStickiness):TCP粘包指的是发送方发送的多个小数据包被接收方一次性接收,形成一个大的数据包。这种情况可能会导致接收方难以正确解析消息的边界,因为多个消息被粘合在一起。TCP是面向流的协议,它不保留消息的边界信息,而是将数据流划分为小的数据块进行传输。TCP拆......
  • Netty源码学习6——netty编码解码器&粘包半包问题的解决
    系列文章目录和关于我零丶引入经过《Netty源码学习4——服务端是处理新连接的&netty的reactor模式和《Netty源码学习5——服务端是如何读取数据的》的学习,我们了解了服务端是如何处理新连接并读取客户端发送的数据的:netty的reactor:主reactor中的NioEventLoop监听accept事件,然......
  • 常见面试题-Netty线程模型以及TCP粘包拆包
    介绍一下Netty使用的线程模型?答:Netty主要基于主从Reactor多线程模型,其中主从Reactor多线程模型将Reactor分为两部分:mainReactor:监听ServerSocket,用来处理网络IO连接建立操作,将建立的SocketChannel指定注册给subReactorsubReactor:和建立起来的socket做数据交互和......
  • 04. 粘包问题
    一、什么是粘包  TCP是流式协议,数据向水流一样粘在一起,没有任何边界区分。如果接收数据没收干净,数据会有残留,就会和下一次的结果混淆在一起,就会出现粘包问题。粘包指的是发送方发送的若干包数据到达接收方时粘成了一包,从接收缓冲区来看,后一包数据的头紧接着前一包数据的尾,出......
  • 10月23日粘包、struct模块以及json模块
    目录粘包如何解决粘包问题呢?struct模块json模块粘包粘包:tcp会把数据量较小,时间间隔较短的数据,当做同一个包发送粘包问题图粘包问题说白了就是客户端传给服务器的数据到服务器的时候有部分数据粘在了一块,而不是一条条的显示粘包产生情况大致图如何解决粘包问题呢?简单的方......
  • TCP 的重传机制;TCP 的粘包和拆包是什么?
    重传包括超时重传、快速重传、带选择确认的重传(SACK)、重复SACK四种。一、TCP重传机制1.1超时重传超时重传,是TCP协议保证数据可靠性的另一个重要机制,其原理是在发送某一个数据以后就开启一个计时器,在一定时间内如果没有得到发送的数据报的ACK报文,那么就重新发送数据,直到发送成......