TCP协议--黏包现象

时间:2022-02-08 10:12:55

# 黏包现象
# 本质: tcp协议是流式传输,信息与信息之间没有边界
# 为什么会造成黏包
# 合包机制: 在发送端,由于两条消息发送的间隔很短,且这两条消息本身很短, 在发送时被合并成一条消息
# 在接收端,由于接受不及时导致两条先后到达的信息在接收端黏在了一起
# 解决黏包问题 -- 自定义协议>> struct模块: 把2**31(2GB)以内的数字变成固定的4个字节
# 简单的形式
# 先发送数据的长度,再发送数据
# 相对规范并复杂的形式
# 先把所有想发送的数据信息放到字典里,
# 再发送字典的长度
# 再发送字典
# 最后发送内容
TCP协议--黏包现象TCP协议--黏包现象
import os
import json
import struct
import socket

sk = socket.socket()
sk.connect(('127.0.0.1', 9001))

filepath = input('请输入文件路径 :')
filename = os.path.basename(filepath)              # os.path.basename 通过文件的路径,得到文件名
filesize = os.path.getsize(filepath)               # 得到文件的大小
dic = {'filename': filename, 'filesize': filesize} # 将文件名, 文件大小写进字典
str_dic = json.dumps(dic)                          # 将字典序列化成字符串形式的字典
bytes_dic = str_dic.encode('utf-8')                # 将字符串形式的字典 转成 字节
len_dic = len(bytes_dic)                           # 得到 字节的长度
bytes_len = struct.pack('i', len_dic)              # 用struck.pack() 将字节 转换成4位的字节
sk.send(bytes_len)                                 # 发送得到的4位字节
sk.send(bytes_dic)                                 # 发送字节
with open(filepath, 'rb') as f:
    content = f.read()                             # 以rb模式 读取到文件中的内容
    sk.send(content)                               # 发送内容
sk.close()

# 先发送字典的长度
# 再发字典 {'filename':xxxx,'filesize':xxxxx}
# 再发文件内容
解决黏包--client端
 
TCP协议--黏包现象TCP协议--黏包现象
import json
import struct
import socket

sk = socket.socket()
sk.bind(('127.0.0.1', 9001))
sk.listen()

conn, addr = sk.accept()
num = conn.recv(4)                               # 接收4位字节
num = struct.unpack('i', num)[0]                 # 读取4位字节, 获得字典长度
str_dic = conn.recv(num).decode('utf-8')         # 读取字典长度, 得到字符串形式的字典
dic = json.loads(str_dic)                        # 将字符串形式的字典反序列化, 得到字典
with open(dic['filename'], 'wb') as f:
    content = conn.recv(dic['filesize'])         # 接收从客户端发来的, dic['filesize']这么大的文件内容
    f.write(content)

conn.close()
sk.close()
解决黏包--server端