解决黏包的问题

一,黏包的触发

复制代码
sk.bind(('127.0.0.1',8090))
sk.listen()
conn,addr=sk.accept()
ret=conn.recv(1)
ret1=conn.recv(1)
ret2=conn.recv(1)
print(ret)
print(ret1)
print(ret2)
conn.close()
sk.close()
复制代码
import socket
sk=socket.socket()
sk.connect(('127.0.0.1',8090))
sk.send(b'hello1234')
sk.close()
C:\Users\hc\AppData\Local\Programs\Python\Python36\python3.exe C:/s9/day32/网络编程.py
b'h'
b'e'
b'l'

Process finished with exit code 0

当接受的字节小于发送的字节数,发送一个数据包,可以有多个recv接收,直到接收完了为止

复制代码
sk.bind(('127.0.0.1',8090))
sk.listen()
conn,addr=sk.accept()
ret=conn.recv(1024)
ret1=conn.recv(2)
ret2=conn.recv(2)
print(ret)
print(ret1)
print(ret2)
conn.close()
sk.close()
复制代码
import socket
sk=socket.socket()
sk.connect(('127.0.0.1',8090))
sk.send(b'h')
sk.send(b'1234')
sk.close()
C:\Users\hc\AppData\Local\Programs\Python\Python36\python3.exe C:/s9/day32/网络编程.py
b'h1234'
b''
b''

Process finished with exit code 0

多个send小数据连在一起,会发生黏包现象,是tcp协议内部的优化算法造成的

在发送端有一个缓存机制

当发送方没有继续发送的时候,接收方还一直有recv在等待接收,此时会返回空的b“   ”的形式

 

解决黏包方法一:

复制代码
import socket
sk=socket.socket()
sk.bind(('127.0.0.1',8090))
sk.listen()
conn,addr=sk.accept()
while 1:
    info=input('>>')
    if info=='q':
        conn.send(b'q')
        break
    conn.send(info.encode('gbk'))
    ret1=conn.recv(1024).decode('utf-8')
    print(ret1)
    conn.send(b'ok')
    ret=conn.recv(int(ret1)).decode('gbk')
    print(ret)
conn.close()
sk.close()
复制代码
复制代码
import socket,subprocess
sk=socket.socket()
sk.connect(('127.0.0.1',8090))
while 1:
    ret=sk.recv(1024).decode('gbk')
    if ret=='q':
        break
    res=subprocess.Popen(ret,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    a=res.stdout.read()
    b=res.stderr.read()
    sk.send((str(len(a)+len(b)).encode('utf-8')))
    sk.recv(1024)
    sk.send(a)
    sk.send(b)
sk.close()
复制代码

由于之前是不知道自己发送的数据是多大的,所以现在首先发送过去的是这个数据的大小,然后在按照数据的长度来接收

好处:确定我们到底要接收多大的数据,

当我们要发送大数据的时候 ,要明确的告诉接收方要发送多大的数据,以便接收方能够准确的接收到所有数据
# 多用在文件传输的过程中

缺点:

不好的地方:多了一次交互
方法二:使用模块,struct
复制代码
import socket,struct

sk=socket.socket()
sk.bind(('127.0.0.1',8090))
sk.listen()
conn,addr=sk.accept()
while 1:
    info=input('>>')
    if info=='q':
        conn.send(b'q')
        break
    conn.send(info.encode('gbk'))
    ret1=conn.recv(4)
    ret1=struct.unpack('i',ret1)[0]
    ret=conn.recv(int(ret1)).decode('gbk')
    print(ret)
conn.close()
sk.close()
复制代码
复制代码
import socket,subprocess,struct
sk=socket.socket()
sk.connect(('127.0.0.1',8090))
while 1:
    ret=sk.recv(1024).decode('gbk')
    if ret=='q':
        break
    res=subprocess.Popen(ret,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    a=res.stdout.read()
    b=res.stderr.read()
    len_1=(len(a)+len(b))
    len_1=struct.pack('i',len_1)
    sk.send(len_1)
    sk.send(a)
    sk.send(b)
sk.close()
复制代码

在网络上传输的所有数据都叫数据包,数据包里的所有数据都叫报文,

报文里有的不止是数据,还有ip地址,mac地址,,端口号

所有的报文都有报头

报文可以是自己定制的一般在比较复杂的时候使用

一般有:

文件的名字,

文件的大小

文件的类型

存储路径

下面写一个用自己设置的报文来写一个下载的程序

复制代码
client:

import
os import json import struct import socket sk = socket.socket() sk.connect(('127.0.0.1',8090)) buffer = 1024 # buffer = 1024 # 发送文件 head = {'filepath':r'C:\Users\hc\Desktop', 'filename':r'单词表--01.xlsx', 'filesize':None} file_path = os.path.join(head['filepath'],head['filename']) filesize = os.path.getsize(file_path) head['filesize'] = filesize json_head = json.dumps(head) # 字典转成了字符串 bytes_head = json_head.encode('utf-8') # 字符串转bytes # 计算head的长度 head_len = len(bytes_head) # 报头的长度 pack_len = struct.pack('i',head_len) sk.send(pack_len) # 先发报头的长度 sk.send(bytes_head) # 再发送bytes类型的报头 with open(file_path,'rb') as f: while filesize: print(filesize) if filesize >= buffer: content = f.read(buffer) # 每次读出来的内容 print('===>',len(content)) sk.send(content) filesize -= buffer else: content = f.read(filesize) sk.send(content) filesize = 0 sk.close()
复制代码
复制代码
server:



import
time import json import socket import struct sk = socket.socket() sk.bind(('127.0.0.1',8090)) sk.listen() buffer = 1024 # buffer = 1024 conn,addr = sk.accept() # 接收 head_len = conn.recv(4) head_len = struct.unpack('i',head_len)[0] json_head = conn.recv(head_len).decode('utf-8') head = json.loads(json_head) filesize = head['filesize'] print(filesize) with open(head['filename'],'wb') as f: while filesize: if filesize >= buffer: print(filesize) content = conn.recv(buffer) f.write(content) filesize -= buffer else: content = conn.recv(filesize) f.write(content) filesize = 0 print('====>',len(content)) print(filesize) print('服务端。。。。') conn.close() sk.close()
复制代码

 

posted @   许光宗  阅读(149)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示