首页 > 其他 > 详细

soket粘包问题及解决方案

时间:2020-09-15 14:16:50      阅读:54      评论:0      收藏:0      [点我收藏+]

一、粘包问题

问题1: 无法确认对方发送过来数据的大小。

import socket

client = socket.socket()

client.connect(
    (127.0.0.1, 9000)
)

while True:

    cmd = input(客户端输入的内容: )

    client.send(cmd.encode(utf-8))

    data = client.recv(19190)
    print(len(data))
    print(data.decode(gbk))
import socket
import subprocess

server = socket.socket()
server.bind((127.0.0.1,9000))
server.listen(5)

while True:
    conn,addr = server.accept()
    print(addr)
    while True:
        try:
            cmd = conn.recv(10)
            if len(cmd) == 0:
                continue
            cmd = cmd.decode(utf-8)  #utf8
            if cmd == q:
                break
            #调用subprocess连接终端,对终端进行操作,并获取操作后正确或错误的结果
            obj = subprocess.Popen(
                #cmd接受的是解码后的字符串
                cmd,shell=True,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE
            )
            #结果交给result变量名
            result = obj.stdout.read()+obj.stderr.read()
            print(len(result))
            print(result.decode(gbk))  #windows系统下默认编码gbk
            #将结果返回给客户端
            conn.send(result)

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

问题2: 在发送数据间隔短并且数据量小的情况下,会将所有数据一次性发送。

import socket

client = socket.socket()

client.connect(
    (127.0.0.1, 9000)
)

client.send(bhello)
client.send(bhello)
client.send(bhello)
import socket

server = socket.socket()

server.bind(
    (127.0.0.1, 9000)
)

server.listen(5)

conn, addr = server.accept()

data = conn.recv(5)
print(data)  # b‘hello‘

data = conn.recv(1024)
print(data)  # b‘hello‘

data = conn.recv(1024)
print(data)  # b‘hello‘

二、粘包问题的解决方案:

粘包问题的解决方案: 确认对方数据的大小。

这里需要用 struct模块

struct是什么?
是一个python内置的模块,它可以将固定长度的数据,打包成固定格式的长度。
固定格式:如 “ i ” 模式
i : 4

struct作用:
可以将真实数据,做成一个固定长度的报头,客户端发送给服务器,服务器可以接受报头,然后对报头进行解包,获取真实数据的长度,进行接收即可

import struct

data = b1111111111111111
print(len(data))  #16

#打包制作报头
header = struct.pack(i,len(data))
print(header)   #b‘\x10\x00\x00\x00‘
print(len(header))  #4

#解包获取真实数据长度 --->得到一个元组,元组中第一个值是真实数据的长度
res = struct.unpack(i,header)[0]
print(res)  #16

无论哪一端先发送数据

 

客户端
- 1) 先制作报头,并发送 (struct)
- 2) 发送真实数据

服务端:
- 1) 接收报头,并解包获取 真实数据长度
- 2) 根据真实数据长度 接收真实数据
recv(真实数据长度)

简单版:

import socket
import struct

client = socket.socket()
client.connect((127.0.0.1, 9000))

while True:
    cmd = input(客户端输入的内容: )
    cmd_bytes = cmd.encode(utf-8)

    header = struct.pack(i,len(cmd_bytes))    #做一个报头
    print(len(header))  #打印报头的长度
    client.send(header)   #发送报头
    client.send(cmd_bytes)      #待服务端确认长度后,发送真实数据长度
    
    headers = client.recv(4)    #接受服务端的报头
    data_len = struct.unpack(i,headers)[0]     #解包
    result = client.recv(data_len)  #接受服务器返回的真实数据的长度

    print(接受服务器返回的真实数据的长度,len(result))
    print(result.decode(gbk))
import socket
import subprocess
import struct

server = socket.socket()
server.bind((127.0.0.1,9000))
server.listen(5)

while True:
    conn,addr = server.accept()
    print(addr)
    while True:
        try:
            header = conn.recv(10)    #获取客户端传过来的报头
            data_len = struct.unpack(i,header)[0]  #解包获取真实数据的长度
              cmd = conn.recv(data_len)       #准备接受真实数据

            if len(cmd) == 0:
                continue
            cmd = cmd.decode(utf-8)  
            if cmd == q:
                break
            #调用subprocess连接终端,对终端进行操作,并获取操作后正确或错误的结果
            obj = subprocess.Popen(
                #cmd接受的是解码后的字符串
                cmd,shell=True,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE
            )
            result = obj.stdout.read()+obj.stderr.read() #获取结果
            print(发送给服务端返回的真实数据的长度, len(result))
            header = struct.pack(i, len(result)) #做报头
            print(len(header))
            conn.send(header)   #发送报头给客户端
            conn.send(result)     #将结果返回给客户端
         
        except Exception as e:
            print(e)
            break
    conn.close()

序列化版:

import socket,json
import struct

client = socket.socket()
client.connect((127.0.0.1,9000))
while True:
    movie_name = input(请输入上传的电影名字:)

    #伪装电影的真实数据
    movie = 1000000
    send_dic ={movie_name:movie_name,
               movie:movie}
    #序列化
    json = json.dumps(send_dic)
    print(json)
    print(json.encode(utf-8))
    print(len(json.encode(utf-8)))
    json_bytes = json.encode(utf-8)

    #做一个报头
    header = struct.pack(i,len(json_bytes))
    #先发送报头
    client.send(header)
    #再发送真实数据
    client.send(json_bytes)
import socket,json
import struct

server = socket.socket()
server.bind((127.0.0.1,9000))
server.listen(5)

while True:
    conn,addr = server.accept()
    while True:
        try:
            #获取客户端传过来的报头
            header = conn.recv(4)
            #解包获取真实数据的长度
            json_len = struct.unpack(i,header)[0]
            #接受json(dic)的真实数据
            json_bytes_data = conn.recv(json_len)
            #将bytes类型数据转为json数据类型
            json_data = json_bytes_data.decode(utf-8)
            #反序列化   json--->dict
            back_dic = json.loads(json_data)
            print(back_dic)
            print(back_dic.get(movie))

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

 

soket粘包问题及解决方案

原文:https://www.cnblogs.com/wddxx/p/13672397.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!