python 网络编程 粘包问题

1.粘包现象
TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。
 
粘包出现原因
使用了优化方法(Nagle算法),将多次间隔较小、数据量小的数据,合并成一个大的数据块,然后进行封包。
简单得说,在流传输中出现,UDP不会出现粘包,因为它有消息边界
1发送端需要等缓冲区满才发送出去,造成粘包
2接收方不及时接收缓冲区的包,造成多个包接收
 
解决方法
接收方创建一预处理线程,对接收到的数据包进行预处理,将粘连的包分开。
 
TCP无保护消息边界的解决
针对这个问题,一般有3种解决方案:
(1)发送固定长度的消息
(2)把消息的尺寸与消息一块发送
(3)使用特殊标记来区分消息间隔
 
2.struct模块
该模块可以把一个类型,如数字,转成固定长度的bytes
 
可以转的类型:

 

 用法:
import struct
 
ret = struct.pack('i',23333)    #i表示int类型,把23333转成固定长度的bytes类型
 
struct.pack('i',ret)    #把bytes转回int

 

3.例子
#以远程执行命令为例讲解决方法
#先发送传输的大小
服务端:
import socket
import struct
sk = socket.socket()
s = ('127.0.0.1', 8081)
sk.bind(s)
sk.listen(2)
conn, addr = sk.accept()
while 1:
    cmd = input('[cmd] #')
    if cmd == 'q':
        break
    conn.send(cmd.encode('utf-8'))
    lens = conn.recv(4)  #接收包长度
    lens = struct.unpack('i',lens)[0]
    info = conn.recv(lens)
    print(info.decode('gbk'))

客户端:
import socket
import subprocess
import struct
sk = socket.socket()
sk.connect(('127.0.0.1',8081))
while 1:
    cmd = sk.recv(1024).decode('gbk')
    res = subprocess.Popen(cmd,shell=True,
                           stdout=subprocess.PIPE,
                           stderr=subprocess.PIPE)
    std = res.stdout.read()+res.stderr.read()
    lens = len(std)
    lens = struct.pack('i', lens)    #把长度转成4个字节的bytes
    sk.send(lens)
    sk.send(std)

 

 
posted @ 2019-02-19 20:53  WaltHwang  阅读(141)  评论(0编辑  收藏  举报