py知识(每日更新) 7.17

socket粘包现象

                      服务端:                  客户端:
第一次 dir             数据418 < 1024            接收418数据
第二次 ipconfig        数据1517 > 1024           接收1024个字节
第三次 dir             数据418 < 1024            接收493个字节

黏包现象的根本原因:缓冲区

系统缓冲区

如果你的网络出现短暂的异常或者波动,接受数据就会出现短暂的中断,影响你的下载或者上传的效率.

但是 缓冲区也是双刃剑,缓冲区解决了上传下载的传输效率的问题,但是带来了粘包的问题

什么情况下产生粘包

1.recv会产生粘包(如果revc的接受数据量小于发送的数据量,第一次只能接受规定的数据量,第二次接受剩余的数据量)
2.send也可能造成粘包 (连续send少量的数据发到输出缓冲区,油鱼缓冲区的机制,也可能在缓冲区中不断积压,多次写入的数据被一次性发送到网络)

解决粘包的方案(revc的工作原理)

# 错误实例
1.扩大recv:
    可以扩大recv的上线 revc(10240000000000000000) 
    不是解决这个问题的根本原因 可能会撑爆内存
2.故意延长recv的时间 
    time.sleep 这样会非常影响效率
# 如何解决
解决粘包现象的思路分析:
    1.当我第二次给服务器发送命令之前,我应该循环recv直至将所有的数据全部取完.
    recv的次数与循环次数相关  3000>>3次 5000>>5次 30000>>30次
    如何限制循环次数?
    当你发送的总bytes个数与接收的总bytes个数相等时,循环结束.
    如何获取发送的总bytes个数: len()
        所以: send两次  总个数 + 总数据
    总个数是什么类型? int() 3400,send需要发送 bytes类型.
    send(总个数)
    ​ 将int 转化成bytes 即可. b'3400'
    ​ 方案一:
    ​ str(3400) -- > '3400' -----> bytes('3400') -----> b'3400' ---> 几个字节? 4个字节
    send(总数据)
1563337531069
你现在继续解决的问题!!!!!
无论总字节个数是多多少? 129 3400 10000 30000 转化成固定长度的bytes.
将不固定长度的int类型,转化成固定长度bytes类型.方便获取头部信息.
    

recv的工作原理

recv从系统缓存区取出固定recv()字节的数据

解决沾包

server

import socket
import subprocess
import struct
import json
phone = socket.socket()
phone.bind(('127.0.0.1', 8888))
phone.listen(5)
# 4.接收连接
print('start')
conn, addr = phone.accept()
while 1:
    try:
        cmd = conn.recv(1024)
        obj = subprocess.Popen(cmd.decode('utf-8'),
                              shell=True,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE,
                              )
        result = obj.stdout.read() + obj.stderr.read()
        result = result.decode('gbk').encode('utf-8')
        # 1.制作表头
        head_dict = {
            'MD5':'896a74sf9647a12we',
            'file_name':'xxx视频',
            'file_size':len(result),
        }
        # 2.将报头字典转化成json字符串
        head_dict_json = json.dumps(head_dict)
        # 3.将json字符串 转化成bytes
        head_dict_json_bytes = head_dict_json.encode('utf-8')
        # 4.获取报头的长度
        head_len = len(head_dict_json_bytes)
        # 5.将长度转化成固定的4个字节
        head_len_bytes = struct.pack('i', head_len)
        # 6.发送固定的4个字节
        conn.send(head_len_bytes)
        # 7.发送报头
        conn.send(head_dict_json_bytes)
        # 8.发送原数据
        conn.send(result)
    except ConnectionResetError:
        break
conn.close()
phone.close()

client

import socket
import struct
phone = socket.socket()
phone.connect(('127.0.0.1', 8888))
# 发消息
while 1:
    cmd = input('>>>').strip()
    phone.send(cmd.encode('utf-8'))
    # 1.接收报头
    head_bytes = phone.recv(4)
    # 2.将报头反解回int类型
    total_size = struct.unpack('i', head_bytes)[0]
    # 3.循环接收原数据
    total_data = b''
    while len(total_data) < total_size:
        total_data += phone.recv(1024)
    print(total_data.decode('gbk'))
phone.close()

转载于:https://www.cnblogs.com/lyoko1996/p/11201849.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值