粘包现象

Posted lowen107

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了粘包现象相关的知识,希望对你有一定的参考价值。

udp协议是不存在粘包现象的,因为它文件的传输方式就是面向包的

tcp协议是有可能出现粘包现象的,它存在粘包的情况有两种:

a.连续发送小包,如果出现网络延迟现象的话,两次发送的消息会一次性被接收

b.如果一次性发送的 ,文件过大,一般来说文件一次性传输大小为1500左右,我们定义接收的大小为1024.文件过大的话就会进行切割

在缓冲区等待发送,有可能会和下一个文件一起被接收.

 

面对粘包有两种方式:

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

server代码

技术分享图片
import socket,subprocess
ip_port=(127.0.0.1,8080)
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

s.bind(ip_port)
s.listen(5)

while True:
    conn,addr=s.accept()
    print(客户端,addr)
    while True:
        msg=conn.recv(1024)
        if not msg:break
        res=subprocess.Popen(msg.decode(utf-8),shell=True,                            stdin=subprocess.PIPE,                         stderr=subprocess.PIPE,                         stdout=subprocess.PIPE)
        err=res.stderr.read()
        if err:
            ret=err
        else:
            ret=res.stdout.read()
        data_length=len(ret)
        conn.send(str(data_length).encode(utf-8))
        data=conn.recv(1024).decode(utf-8)
        if data == recv_ready:
            conn.sendall(ret)
    conn.close()

tcp_server.py
tcp_server.py

 cilent代码

技术分享图片
import socket,time
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
res=s.connect_ex((127.0.0.1,8080))

while True:
    msg=input(>>: ).strip()
    if len(msg) == 0:continue
    if msg == quit:break

    s.send(msg.encode(utf-8))
    length=int(s.recv(1024).decode(utf-8))
    s.send(recv_ready.encode(utf-8))
    send_size=0
    recv_size=0
    data=b‘‘
    while recv_size < length:
        data+=s.recv(1024)
        recv_size+=len(data)


    print(data.decode(utf-8))
tcp_cilent.py

(2)解决方案(二):

通过struck模块将需要发送的内容的长度进行打包,打包成一个4字节长度的数据发送到对端,对端只要取出前4个字节,然后对这四个字节的数据进行解包,接收数据端就知道我们总数据长度是多少,然后同一文件就会进行一次封装.
server端
技术分享图片
import socket,struct,json
import subprocess
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

phone.bind((127.0.0.1,8080))
phone.listen(5)

while True:
    conn,addr=phone.accept()
    while True:
        cmd=conn.recv(1024)
        if not cmd:break
        print(cmd: %s %cmd)

        res=subprocess.Popen(cmd.decode(utf-8),
                             shell=True,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        err=res.stderr.read()
        print(err)
        if err:
            back_msg=err
        else:
            back_msg=res.stdout.read()

        headers={data_size:len(back_msg)}
        head_json=json.dumps(headers)
        head_json_bytes=bytes(head_json,encoding=utf-8)

        conn.send(struct.pack(i,len(head_json_bytes))) #先发报头的长度
        conn.send(head_json_bytes) #再发报头
        conn.sendall(back_msg) #在发真实的内容

    conn.close()
ctp_server.py

cilent端口

技术分享图片
import struct,json,socket

ip_port=(127.0.0.1,8080)
client=socket(AF_INET,SOCK_STREAM)
client.connect(ip_port)

while True:
    cmd=input(>>: )
    if not cmd:continue
    client.send(bytes(cmd,encoding=utf-8))

    head=client.recv(4)
    head_json_len=struct.unpack(i,head)[0]
    head_json=json.loads(client.recv(head_json_len).decode(utf-8))
    data_len=head_json[data_size]

    recv_size=0
    recv_data=b‘‘
    while recv_size < data_len:
        recv_data+=client.recv(1024)
        recv_size+=len(recv_data)

    #print(recv_data.decode(‘utf-8‘))
    print(recv_data.decode(gbk)) #windows默认gbk编码
tcp_client.py

 

以上是关于粘包现象的主要内容,如果未能解决你的问题,请参考以下文章

socket网络编程:粘包现象以及解决方法(代码完善)

网络编程基础之粘包现象

详解啥是 TCP 粘包和拆包现象并演示 Netty 是如何解决的

透过现象看本质,我找到了Netty粘包与半包的这几种解决方案。

Netty进阶——粘包与半包(现象分析)

Netty进阶——粘包与半包(现象分析)