加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

黏包问题的成因与解决方案

发布时间:2020-12-17 00:01:05 所属栏目:Python 来源:网络整理
导读:一、黏包成因 tcp协议的拆包机制 面向流的通信特点和Nagle算法 总结: 黏包有两种: 二、黏包的解决方案 1,问题的根源在于,接收端不知道发送端将要传送的字节流的长度,所以解决粘包的方法就是围绕,如何让发送端在发送数据前,把自己将要发送的字节流总大

一、黏包成因

tcp协议的拆包机制

面向流的通信特点和Nagle算法

总结:

黏包有两种:

二、黏包的解决方案

1,问题的根源在于,接收端不知道发送端将要传送的字节流的长度,所以解决粘包的方法就是围绕,如何让发送端在发送数据前,把自己将要发送的字节流总大小让接收端知晓,然后接收端来一个死循环接收完所有数据。

=(,8080=1s.bind(ip_port)
s.listen(
5<span style="color: #000000">)

<span style="color: #0000ff">while<span style="color: #000000"> True:
conn,addr=<span style="color: #000000">s.accept()
<span style="color: #0000ff">print(<span style="color: #800000">'<span style="color: #800000">客户端<span style="color: #800000">'<span style="color: #000000">,addr)
<span style="color: #0000ff">while<span style="color: #000000"> True:
msg=conn.recv(1024<span style="color: #000000">)
<span style="color: #0000ff">if <span style="color: #0000ff">not msg:<span style="color: #0000ff">break<span style="color: #000000">
res=subprocess.Popen(msg.decode(<span style="color: #800000">'<span style="color: #800000">utf-8<span style="color: #800000">'),shell=<span style="color: #000000">True,
stdin=<span style="color: #000000">subprocess.PIPE,
stderr=<span style="color: #000000">subprocess.PIPE,
stdout=<span style="color: #000000">subprocess.PIPE)
err=<span style="color: #000000">res.stderr.read()
<span style="color: #0000ff">if<span style="color: #000000"> err:
ret=<span style="color: #000000">err
<span style="color: #0000ff">else<span style="color: #000000">:
ret=<span style="color: #000000">res.stdout.read()
data_length=<span style="color: #000000">len(ret)
conn.send(str(data_length).encode(<span style="color: #800000">'<span style="color: #800000">utf-8<span style="color: #800000">'<span style="color: #000000">))
data=conn.recv(1024).decode(<span style="color: #800000">'<span style="color: #800000">utf-8<span style="color: #800000">'<span style="color: #000000">)
<span style="color: #0000ff">if data == <span style="color: #800000">'<span style="color: #800000">recv_ready<span style="color: #800000">'<span style="color: #000000">:
conn.sendall(ret)
conn.close()

服务端

==s.connect_ex((,8080<span style="color: #0000ff">while<span style="color: #000000"> True:
msg
=input(<span style="color: #800000">'
<span style="color: #800000">>>:
<span style="color: #800000">'
<span style="color: #000000">).strip()
<span style="color: #0000ff">if
len(msg) == 0:<span style="color: #0000ff">continue

<span style="color: #0000ff">if msg == <span style="color: #800000">'<span style="color: #800000">quit<span style="color: #800000">':<span style="color: #0000ff">break<span style="color: #000000">

s.send(msg.encode(</span><span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;utf-8</span><span style="color: #800000"&gt;'</span><span style="color: #000000"&gt;))
length</span>=int(s.recv(1024).decode(<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;utf-8</span><span style="color: #800000"&gt;'</span><span style="color: #000000"&gt;))
s.send(</span><span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;recv_ready</span><span style="color: #800000"&gt;'</span>.encode(<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;utf-8</span><span style="color: #800000"&gt;'</span><span style="color: #000000"&gt;))
send_size</span>=<span style="color: #000000"&gt;0
recv_size</span>=<span style="color: #000000"&gt;0
data</span>=b<span style="color: #800000"&gt;''</span>
<span style="color: #0000ff"&gt;while</span> recv_size <<span style="color: #000000"&gt; length:
    data</span>+=s.recv(1024<span style="color: #000000"&gt;)
    recv_size</span>+=<span style="color: #000000"&gt;len(data)


</span><span style="color: #0000ff"&gt;print</span>(data.decode(<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;utf-8</span><span style="color: #800000"&gt;'</span><span style="color: #000000"&gt;))

客户端

2.使用time模块,在每次send的时候加入一个time.sleep(0.01),这种方法可以有效地隔开两次send,断开系统的优化,此种方法虽然可以解决黏包问题,但是会造成发送数据时间长

=,8090conn,addr =<span style="color: #000000"> sk.accept()
ret1
= conn.recv(12<span style="color: #000000">)
<span style="color: #0000ff">print
<span style="color: #000000">(ret1)
ret2
= conn.recv(12) <span style="color: #008000">#
ret3 = conn.recv(12) <span style="color: #008000">#
<span style="color: #0000ff">print<span style="color: #000000">(ret2)
<span style="color: #0000ff">print<span style="color: #000000">(ret3)
conn.close()
sk.close()

sk =<span style="color: #000000"> socket.socket()
sk.connect((
<span style="color: #800000">'<span style="color: #800000">127.0.0.1<span style="color: #800000">',8090<span style="color: #000000">))

sk.send(b<span style="color: #800000">'<span style="color: #800000">hello<span style="color: #800000">'<span style="color: #000000">)
<span style="color: #0000ff">import<span style="color: #000000"> time
time.sleep(0.01<span style="color: #000000">)
sk.send(b<span style="color: #800000">'<span style="color: #800000">egg<span style="color: #800000">'<span style="color: #000000">)

sk.close()

=socket.socket() sk.bind((,8080)) sk.listen() buffer =1024 conn,addr =sk.accept() head_len=conn.recv(4) head_len =struct.unpack(,head_len)[0] json_head =conn.recv(head_len).decode() head =json.loads(json_head) filesize =head[] (filesize) with open(r%head[],)as f: filesize: filesize >=buffer:= buffer值,buffer值是设定的一次接收多少字节的内容 (filesize) content =conn.recv(buffer) f.write(content) filesize -=buffer : content ==((
=,8090=1024={:r:r:None} file_path =os.path.join(head[],head[]) filesize = os.path.getsize(file_path) head[] =filesize json_head =json.dumps(head) bytes_head =json_head.encode() head_len =len(bytes_head) pack_len =struct.pack(,head_len) sk.send(pack_len) sk.send(bytes_head) with open(file_path, filesize>==(-===

为什么会出现黏包问题?

首先只有在TCP协议中才会出现黏包现象

是因为TCP协议是面向流的协议

在发送的数据传输的过程中海油缓存机制来避免数据丢失

因为在连续发送小数据的时候、以及接收大小不符的时候都容易出现黏包现象

本质还是因为我们在接收数据的时候不知道发送的数据的长短

解决黏包问题

在传输大量数据之前先告诉数据量的大小。

4,使用struct解决黏包?

=1) ,8080phone.listen(5<span style="color: #000000">)

<span style="color: #0000ff">while<span style="color: #000000"> True:
conn,addr=<span style="color: #000000">phone.accept()
<span style="color: #0000ff">while<span style="color: #000000"> True:
cmd=conn.recv(1024<span style="color: #000000">)
<span style="color: #0000ff">if <span style="color: #0000ff">not cmd:<span style="color: #0000ff">break
<span style="color: #0000ff">print(<span style="color: #800000">'<span style="color: #800000">cmd: %s<span style="color: #800000">' %<span style="color: #000000">cmd)

    res</span>=subprocess.Popen(cmd.decode(<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;utf-8</span><span style="color: #800000"&gt;'</span><span style="color: #000000"&gt;),shell</span>=<span style="color: #000000"&gt;True,stdout</span>=<span style="color: #000000"&gt;subprocess.PIPE,stderr</span>=<span style="color: #000000"&gt;subprocess.PIPE)
    err</span>=<span style="color: #000000"&gt;res.stderr.read()
    </span><span style="color: #0000ff"&gt;print</span><span style="color: #000000"&gt;(err)
    </span><span style="color: #0000ff"&gt;if</span><span style="color: #000000"&gt; err:
        back_msg</span>=<span style="color: #000000"&gt;err
    </span><span style="color: #0000ff"&gt;else</span><span style="color: #000000"&gt;:
        back_msg</span>=<span style="color: #000000"&gt;res.stdout.read()


    conn.send(struct.pack(</span><span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;i</span><span style="color: #800000"&gt;'</span>,len(back_msg))) <span style="color: #008000"&gt;#</span><span style="color: #008000"&gt;先发back_msg的长度</span>
    conn.sendall(back_msg) <span style="color: #008000"&gt;#</span><span style="color: #008000"&gt;在发真实的内容</span>

<span style="color: #000000">
conn.close()

s=<span style="color: #000000">socket.socket(socket.AF_INET,8080<span style="color: #000000">))

<span style="color: #0000ff">while<span style="color: #000000"> True:
msg=input(<span style="color: #800000">'<span style="color: #800000">>>: <span style="color: #800000">'<span style="color: #000000">).strip()
<span style="color: #0000ff">if len(msg) == 0:<span style="color: #0000ff">continue
<span style="color: #0000ff">if msg == <span style="color: #800000">'<span style="color: #800000">quit<span style="color: #800000">':<span style="color: #0000ff">break<span style="color: #000000">

s.send(msg.encode(</span><span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;utf-8</span><span style="color: #800000"&gt;'</span><span style="color: #000000"&gt;))



l</span>=s.recv(4<span style="color: #000000"&gt;)
x</span>=struct.unpack(<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;i</span><span style="color: #800000"&gt;'</span><span style="color: #000000"&gt;,l)[0]
</span><span style="color: #0000ff"&gt;print</span><span style="color: #000000"&gt;(type(x),x)
</span><span style="color: #008000"&gt;#</span><span style="color: #008000"&gt; print(struct.unpack('I',l))</span>
r_s=<span style="color: #000000"&gt;0
data</span>=b<span style="color: #800000"&gt;''</span>
<span style="color: #0000ff"&gt;while</span> r_s <<span style="color: #000000"&gt; x:
    r_d</span>=s.recv(1024<span style="color: #000000"&gt;)
    data</span>+=<span style="color: #000000"&gt;r_d
    r_s</span>+=<span style="color: #000000"&gt;len(r_d)

</span><span style="color: #008000"&gt;#</span><span style="color: #008000"&gt; print(data.decode('utf-8'))</span>
<span style="color: #0000ff"&gt;print</span>(data.decode(<span style="color: #800000"&gt;'</span><span style="color: #800000"&gt;gbk</span><span style="color: #800000"&gt;'</span>)) <span style="color: #008000"&gt;#</span><span style="color: #008000"&gt;windows默认gbk编码</span></pre>

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读