粘包,文件传输

TCP的粘包问题
TCP 流式协议
基于数据流的协议


接收方产生粘包问题
1. 接收方不清楚数据有多长 只接受了数据的一部分
2. 接收方多读了数据
发送方产生的粘包问题
3.操作系统没有及时发送前一次的数据 导致两次数据黏在了一起

TCP nigle优化机制
如果多次发送数据的数据量小并且时间间隔短:会把这一堆数据聚合在一起一次性发送
目的是为了降低网络传输次数


UDP基于数据报的传输协议 不会发生粘包问题 因为数据是以报文的形式存在
每次发送都是以数据报的形式 对方接收的也是一个数据报

粘包产生的根本原因是接收方不清楚数据的长度
解决粘包的核心思路:就是先通知接收方 要发送的数据的长度
再发送真实数据



问题在于 数据长度 也是不确定的
对方也不清楚 长度信息 到底几个字节

想办法将长度信息所占的字节数固定下来

导入struct模块
q为长整型 8位字节
l为整型 4位字节


import struct

# q表示longlong类型 占八个字节
b = struct.pack("q",10000000000000)
print(b)
print(len(b))

# 解包 把二进制还原为整型
# 返回的是一个元组 第0 个表示原始数据
num = struct.unpack("q",b)

print(num)


import socket,struct

c=socket.socket()
c.connect(('127.0.0.1',8808))

data='hello 我林霄 see you tomorrow'.encode('utf-8')
#给接收方发送数据的长度
length=len(data)
#将整型的长度 转为固定长度的字节
len_data=struct.pack('q',length)
#发送长度信息
c.send(len_data)
#发送真实数据
c.send(data)
import socket,struct
s=socket.socket()
s.bind(('127.0.0.1',8808))
s.listen()
c,addr=s.accept()
# 先接收长度
# 有可能 长度信息和真实数据也黏在一起 无法取出长度信息

# 解决方案是  把长度信息 转换为一个固定字节数的二进制数据
# 1      4个字节的bytes
# 2      4个字节的bytes
# 20000  4个字节的bytes
# 接收数据的长度信息
length=struct.unpack('q',c.recv(8))[0]
print('长度为:%s'%length)
data=c.recv(length).decode('utf-8')
print(data)

 文件传输:

import hashlib
def get_MD5(file_name):
    # 用于计算某个文件的MD5值
    with open(file_name,"rb") as f:
        m = hashlib.md5()
        while True:
            data = f.read(1024)
            if not data:
                break
            m.update(f.read())
        return m.hexdigest()

if __name__ == '__main__':
    print(get_MD5(r"1.网络协议回顾.mp4"))
tool
"""
发送文件
1.连接服务器
2.打开文件
3.读取文件的长度信息并发送给服务器
4.读取文件内容
5.发送文件数据


不仅要上传文件
还要传一些文件的相关信息

文件名
MD5

"""

import socket
import struct
import json
import os
import tool
c = socket.socket()
c.connect(("127.0.0.1",1688))

path = r"D:python6期视频1.网络协议回顾.mp4"

# 待发送的两段数据
file_name = "1.网络协议回顾.mp4"
MD5 = "ASAASAS121212"
# 发送的文件长度
file_size = os.path.getsize(path)

#将数据组装为字典
info_dic = {"file_name":file_name,"MD5":tool.get_MD5(path),"file_size":file_size}
# 将字典转为json的字符串
json_str = json.dumps(info_dic)

# 获取文件信息的长度
json_len = struct.pack("q",len(json_str.encode("utf-8")))

# 发送长度
c.send(json_len)

# 发送文件信息
c.send(json_str.encode("utf-8"))


# 循环发送文件数据
with open(path,"rb") as f:
    while True:
        data = f.read(1024)
        if not data:
            break
        c.send(data)
发送文件
import socket
import struct
import json
"""
接收文件
1.建立连接
2.获取文件的长度信息
3.接收文件数据写入文件中

"""
import os
import tool
s = socket.socket()
s.bind(("127.0.0.1",1688))
s.listen()
c,addr = s.accept()

# 先接受文件信息的字典
length = struct.unpack("q",c.recv(8))[0]
# 文件信息
info = c.recv(length).decode("utf-8")

# 反序列化
info_dic = json.loads(info)
print(info_dic)


print("文件总长:%s" % info_dic["file_size"])

#已经接收的长度
curren_size = 0
file = open(info_dic["file_name"],"wb")
# 接收真实数据  # 建议循环接收 以保证缓冲区不会超出内存
while curren_size < info_dic["file_size"]:
    data = c.recv(1024)
    if not data:
        print("对方下线了")
        break
    # 写入数据
    file.write(data)
    curren_size += len(data) # 记录已经接收的长度
    # print("当前已经接收:%s" % curren_size)

file.close()
print("接收完毕!")

if info_dic["MD5"] == tool.get_MD5(info_dic["file_name"]):
    print("MD5校验成功!")
else:
    print("MD5校验失败! 你下载的是盗版的 请到官网下载 www.oldboyedu.com!")
接收文件
原文地址:https://www.cnblogs.com/gengbinjia/p/10457222.html