网络编程之黏包现象

<关于python黏包现象的那些事>

1.黏包

1.1  什么是黏包?

同时执行多条命令后,得到的结果很可能只有一部分,在执行其他命令的时候又接收到之前执行的另外一部分结果,这种显现是黏包。

注释:黏包只会发生在tcp协议中,这后边会将原因。

1.2  黏包成因

  • 关于tcp:基于tcp的套接字客户端往服务端上传文件,发送文件内容是按照一段一段的字节流发送的,在接收方看了,根本不知道该文件的字节流是从何处可似乎的,从何处结束。此外发送端引起的黏包是由tcp协议本身造成的,tcp为提高传输效率,发送方往往要收集到足够多的数据后才发送一个tcp段。若连续几次需要send数据很少,会根据优化算法合并到一段一次发,这样形成一次发。
  • 关于udp不会发生黏包:是无链接的,面向消息的,提高效率服务,不会使用块的合并优化算法,由于ydp支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的udp包,在每个udp包都有了消息头(消息来源地址,端口信息),这样很容易区分。即有消息保护边界。

1.3  发生黏包的两种情况

1    发送方的缓存机制:发送端需要等缓冲区满才发送出去,造成黏包(发送数据时间间隔很短,数据很小会合到一起,产生黏包)

2    接收方的缓存机制:接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只接收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生黏包)

总结:   表面上:黏包问题主要是因为发送方和接收方的缓存机制,tcp协议面向流通信的特点。

    实际上:主要是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据造成的。

1.4  黏包的解决方案

解决方案1

如何让发送端在发送数据前,把自己将要发送的字节流总大小让接收方知晓,然后来一个死循环接收完所有数据。

import struct
import socket 
sk=socket.socket()
sk.bind(('127.0.0.1',9000))
sk.listen()
conn,addr=sk.accept()
while True:
    s=input(/>>>/).encode('utf-8')
    pack_num=struct.pack('i',len(s))
    conn.send(pack_num)
    conn.send(s)
conn.close()
sk.close()
import socket
import struct
sk=socket.socket()
sk.connect(('127.0.0.1',9000))
while True:
    pack_num=sk.recv(4)
    num=struct.unpack('i',pack_num)[0]
    ret=sk.recv(num)
    print(ret.decode('utf-8'))
sk.close()

  

解决方案进阶

stuct模块

该模块可以把一个类型,如数字转成固定长度的bytes

>>> struct.pack('i',1111111111111)

struct.error: 'i' format requires -2147483648 <= number <= 2147483647 #这个是范围

猜你喜欢

转载自www.cnblogs.com/13507215809qwer-/p/9658218.html