设为首页 加入收藏

TOP

粘包(一)
2019-06-12 18:06:10 】 浏览:46
Tags:粘包

参考资料:https://www.jb51.net/article/139118.htm

粘包的产生:

1 直接原因

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

2  根本原因

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

 

 

解决粘包:

方法一:(先发)

客户端:

import socket
import json
sock=socket.socket()
sock.bind(('127.0.0.1',9000,))
sock.listen(5)
while 1:
    print("server is working....")
    conn,addr=sock.accept()
    while 1:
        data=conn.recv(1024).decode("utf8")#接收的是json的字符串
        fileinfo=json.loads(data)  #把接受接收的json类型的字符串loads成字典
        print("fileinfo",fileinfo) #打印出fileinfo {'action': 'put', 'filename': '1.jpg', 'filesize': 16256}
        #文件信息
        action = fileinfo.get("action")
        filename = fileinfo.get("filename")
        filesize = fileinfo.get("filesize")
        conn.send(b'quick')
        #接收文件数据
        with open('put/'+filename,"wb") as f:
            recv_data_length=0
            while recv_data_length <filesize:
                data=conn.recv(1024)
                recv_data_length+=len(data) #len(data)是每次接收数据的长度
                f.write(data)
        print("文件总大小:%s,文件成功加收:%s" % (filesize, recv_data_length))
        print("接收成功....")
服务端:
import socket
import os
import json
'''
客户端思路:
1.创建socket的对象
2.连接服务器
3.实现可以循环的额发送命令
    3.1让用户输入命令
    3.2分解命令
    3.3利用os模块得到文件的大小
    3.4发送文件的信息(action,filename,filesize,)可以将信息放到字典中
    3.5向服务器发送文件的信息 利用json将字典变成字符串encode成字节发送到服务器
    3.6服务器接收文件信息发送一个确认信息,客户端接收数据
    3.7循环发送文件
'''
sock = socket.socket()
sock.connect(('127.0.0.1', 9000))
while 1:
    cmd = input("请输入命令>>>")  # put 1.jpg
    action, filename = cmd.strip().split(" ")  # action 命令  filename 文件名
    filesize = os.path.getsize(filename)
    fileinfo = {
        "action": action,
        "filename": filename,
        "filesize": filesize,
    }
    fileinfo_json=json.dumps(fileinfo).encode("utf8")
    sock.send(fileinfo_json)
    #确认服务端接收到了文件信息
    haha=sock.recv(1024).decode("utf8")
    if haha =='quick':
        #发送文件
        with open(filename,"rb") as f:
            for line in f:
                sock.send(line)
    else:
        print("服务器异常")
方法二:(利用struct模块防止粘包产生的报错)
服务端:
import socket
import json
import time
import hashlib
import struct
sock = socket.socket()
sock.bind(('127.0.0.1', 9000,))
sock.listen(5)
while 1:
    print("server is working....")
    conn, addr = sock.accept()
    while 1:
        ##得到fileinfo_json打包的结果
        fileinfo_json_lengthpack=conn.recv(4)
###########得到的是fileinfo_json的长度 但是unpack的结果是一个元组(57,)
        fileinfo_json_length=struct.unpack("i",fileinfo_json_lengthpack)[0]
        # print(fileinfo_json_length)
        #接收fileinfo_json的字符串
        fileinfo_json=conn.recv(fileinfo_json_length).decode("utf8")
        #用loads得到字典
        fileinfo=json.loads(fileinfo_json)
        # fileinfo_json = conn.recv(1024).decode("utf8")  # 接收的是json的字符串
        # fileinfo = json.loads(fileinfo_json)  # 用json的loads fileinfo_json 使其变成字典
        # print("fileinfo_json", fileinfo_json)
        # 文件信息
        action = fileinfo.get("action")
        filename = fileinfo.get("filename")
        filesize = fileinfo.get("filesize")
        # 循环接收文件
        with open('put/' + filename, "wb") as f:
            recv_data_length = 0
            while recv_data_length < filesize:
                data = conn.recv(1024)
                recv_data_length += len(data)  # len(data)是每次接收数据的长度
                f.write(data)
        print("文件总大小:%s,文件成功加收:%s" % (filesize, recv_data_l  
		
粘包(一) https://www.cppentry.com/bencandy.php?fid=77&id=226587

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇python CGI编程---Apache服务安装 下一篇补之前 如何改变jupyter打开文件..