码迷,mamicode.com
首页 > 其他好文 > 详细

处理粘包成绩

时间:2019-09-13 17:28:04      浏览:91018      评论:0      收藏:0      [点我收藏+]

标签:客户端连接   port   粘包   大年夜小   +=   技巧   alt   enc   发送数据   

处理粘包成绩

一、处理粘包成绩方法一

成绩的根源在于,接收端不知道发送端将要传送的字撙节的长度,所以处理粘包的办法就是环绕,若何让发送端在发送数据前,把本身将要发送的字撙节总大年夜小让接收端知晓,然后接收端来一个逝世轮回接收完所稀有据。

1.1 办事器

import socket
import subprocess
import struct

soc = socket.socket()
soc.bind(('127.0.0.1', 8001))
soc.listen(4)
while True:
    print("等待客户端连接")
    conn, addr = soc.accept()
    print("有个客户端连接上:", addr)

    while True:
        try:
            data = conn.recv(1024)
            if len(data) == 0:
                break
            print(data)
            obj = subprocess.Popen(data.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            # 履行成果为b格局, gbk编码(windows平台)
            msg = obj.stdout.read()

            """
            发送的时辰须要把长度计算出来
            头必须是固定的长度
            选取出要发送数据的长度
            """
            leng = len(msg)
            # head是固定的四个字节
            head = struct.pack('i', leng)

            # 发送头
            conn.send(head)
            # 发送内容
            conn.send(msg)


        except Exception as e:
            print(e)
            break
    conn.close()

soc.close()

1.2 客户端

import socket
import struct

soc = socket.socket()

soc.connect(('127.0.0.1', 8001))

while True:
    in_s = input("请输入要履行敕令:")
    soc.send(in_s.encode('utf-8'))
    head = soc.recv(4)
    lengs = struct.unpack('i', head)[0]

    count = 0
    data_total = b""
    while count < lengs:
        if lengs < 1024:
            # 假设接收的数据小于1024,直接接收数据的大年夜小
            data = soc.recv(lengs)
        else:
            # 假设接收的数据大年夜于1024
            if lengs - count > 1024:
                # 总数据长度减去count(今朝收到若干, count就是若干), 假设还大年夜于1024,在收1024

                data = soc.recv(1024)
            else:
                # 总数据长度减去count(今朝收到若干,count就是若干), 假设小于1024, 只收剩下的部分便可
                data = soc.recv(lengs- count)

        data_total += data
        count += len(data)

    print(data_total.decode('gbk'))

缺点:

法式榜样的运转速度远快于搜集传输速度,所以在发送一段字节前,先用send去发送该字撙节长度,这类方法会缩小年夜搜集延迟带来的性能消耗

2、弥补struct模块

2.1 简单实用

[技巧图片

import struct
import json

# 'i'是格局
try:
    obj = struct.pack('i', 1222222222223)
except Exception as e:
    print(e)
    obj = struct.pack('i', 1222)
print(obj, len(obj))

‘i‘ format requires -2147483648 <= number <= 2147483647
b‘\xc6\x04\x00\x00‘ 4

res = struct.unpack('i', obj)
print(res[0])

1222

3、处理粘包成绩终结版

处理粘包成绩的核心就是:为字撙节加上自定义固定长度报头,报头中包含字撙节长度,然后一次send到对端,对端在接收时,先从缓存中取出定长的报头,然后再取真实数据。

3.1 应用struct模块创建报头

import json
import struct

header_dic = {
    'filename': 'a.txt',
    'total_size':
    111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223131232,
    'hash': 'asdf123123x123213x'
}

header_json = json.dumps(header_dic)

header_bytes = header_json.encode('utf-8')
print(len(header_bytes))

# 'i'是格局
obj = struct.pack('i', len(header_bytes))
print(obj, len(obj))

223
b‘\xdf\x00\x00\x00‘ 4

res = struct.unpack('i', obj)
print(res[0])

223

3.2办事端

import socket
import subprocess
import struct

soc = socket.socket()
soc.bind(('127.0.0.1', 8001))
soc.listen(4)
while True:
    print("等待客户端连接")
    conn, addr = soc.accept()
    print("有个客户端连接上:", addr)

    while True:
        try:
            data = conn.recv(1024)
            if len(data) == 0:
                break
            print(data)
            obj = subprocess.Popen(data.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            # 履行成果为b格局, gbk编码(windows平台)
            msg = obj.stdout.read()

            """
            发送的时辰须要把长度计算出来
            头必须是固定的长度
            选取出要发送数据的长度
            """
            leng = len(msg)
            # head是固定的四个字节
            head = struct.pack('i', leng)

            # 发送头
            conn.send(head)
            # 发送内容
            conn.send(msg)


        except Exception as e:
            print(e)
            break
    conn.close()

soc.close()
3.3 客户端
import socket
import struct

soc = socket.socket()

soc.connect(('127.0.0.1', 8001))

while True:
    in_s = input("请输入要履行敕令:")
    soc.send(in_s.encode('utf-8'))
    head = soc.recv(4)
    lengs = struct.unpack('i', head)[0]

    count = 0
    data_total = b""
    while count < lengs:
        if lengs < 1024:
            # 假设接收的数据小于1024,直接接收数据的大年夜小
            data = soc.recv(lengs)
        else:
            # 假设接收的数据大年夜于1024
            if lengs - count > 1024:
                # 总数据长度减去count(今朝收到若干, count就是若干), 假设还大年夜于1024,在收1024

                data = soc.recv(1024)
            else:
                # 总数据长度减去count(今朝收到若干,count就是若干), 假设小于1024, 只收剩下的部分便可
                data = soc.recv(lengs- count)

        data_total += data
        count += len(data)

    print(data_total.decode('gbk'))

处理粘包成绩

标签:客户端连接   port   粘包   大年夜小   +=   技巧   alt   enc   发送数据   

原文地址:https://www.cnblogs.com/randysun/p/11516999.html

(0)
(0)
   
告发
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权一切 京ICP备13008772号-2
迷上了代码!