1、缓冲区和subprocess模块

  1.1  缓冲区( 当send()内容超过输入缓冲区大小或recv()接收内容超过输出缓冲区大小时旧版本(py3.5以前)是会直接报错的, py3.5以后如果出错内部机制会直接处理错误, 处理方式类似于sendall()的方式循环发送去缓存区. )

    

  每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区。

  write()/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送到目标机器。一旦将数据写入到缓冲区,函数就可以成功返回,不管它们有没有到达目标机器,也不管它们何时被发送到网络,这些都是TCP协议负责的事情。

  TCP协议独立于 write()/send() 函数,数据有可能刚被写入缓冲区就发送到网络,也可能在缓冲区中不断积压,多次写入的数据被一次性发送到网络,这取决于当时的网络情况、当前线程是否空闲等诸多因素,不由程序员控制。

  read()/recv() 函数也是如此,也从输入缓冲区中读取数据,而不是直接从网络中读取。

  2.2  解释器调用系统指令----> subprocess

 import subprocess      # 解释器操作cmd的模块
recv_msg = input("输入cmd命令: ")
cmd_obj = subprocess.Popen(
recv_msg, # 输入的cmd指令,"dir", "ipconfig" ......
shell=True, # shell = True, 即相当于使用cmd窗口
stdout=subprocess.PIPE, # 标准输出信息都在PIPE管道中
stderr=subprocess.PIPE, # 出错信息也在PIPE管道中
)
cmd_msg = cmd_obj.stdout.read().decode("gbk") # 对象调用里面的stdout属性, 并读取出来.(和计算机交互一般都以GBK编码解码)
print(cmd_msg)

subprocess模块

2、黏包

  产生黏包的原因? 主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的

  现象1: 连续send两个比较小点的数据时, 在网速各方面都很流畅情况下是不会产生黏包现象的(用time.sleep模拟), 当网速或其他原因造成上传速度变慢, TCP内部的Nagle算法和延迟ACK机制, 会减少大量小包的连续发送, 所以会将比较小的连续发送的数据合并成一个比较大的包, 这是第一种黏包;

  现象2: send()给缓冲区扔了太多数据, 超过缓冲区的大小就会报错, 每个IP包一般最大为1500b, 如果超过这个值就会被拆包发送, 第一次剩下的数据有可能和第二次发送的数据一起连在一起被接收, 这就是第二种黏包;

3、如何解决黏包现象?

  3.1 了解一下struct模块 ----> 其实就是定义一种结构,里面包含不同类型的数据(int,char,bool等等),方便对某一结构对象进行处理。该模块的主要作用就是对python基本类型值与一个四位二进制数类型间的转化.

  struct模块支持打包哪些数据类型?

  struct.pack()  可以将struct支持的数据类型打包成一个对应长度二进制的数, 如果给 "int" 类型的数字打包的话, 结果就是一个4位二进制的数.

  struct.unpack()  将打包成的二进制数解包回来, 结果是一个元组.

 import struct
numb = 152856900
numb_bytes = struct.pack("i",numb) # 把int 类型的numb打包成一个4位二进制的数( (数字位数不能超过10位,有符号(-)的数字不能超过11位)转化后的结果都是4位),
# "i"表示是一个整数 b'Di\x1c\t'
print(numb_bytes) numb = struct.unpack("i",numb_bytes) # 结果是一个元组形式. (152856900,)
print(numb)

struct模块

  如何解决黏包现象?   ---->  让接收方知道自己要接收的字节流总长度, 然后按这个长度接收就行.

    第一种方案: 发送方先把字节流的总长度发给接收方, 接收方在接到总长度后给发送方传达一个确认信息, 发送方开始传数据, 接收方循环接收数据, 直到接受到的字节总长度等于发送方发来的字节流总长度.

 import socket
import subprocess # 服务端(发送方)
server = socket.socket()
ip_port = ("192.168.12.42",8520)
server.bind(ip_port)
server.listen(4)
conn,addr = server.accept() while 1:
recv_msg = str(conn.recv(1024),"utf8")
cmd_obj = subprocess.Popen(
recv_msg,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
cmd_msg = cmd_obj.stdout.read() * 20
cmd_msg_len = bytes(str(len(cmd_msg)),"utf8")
conn.send(cmd_msg_len) # 先发送一个总的字节长度
has_send = 0
while has_send < len(cmd_msg): # 发送方循环发送
every_send = cmd_msg[has_send:has_send + 1024]
conn.send(every_send)
has_send += len(every_send) # 客户端(接收方)
client = socket.socket()
ip_port = ("192.168.12.42",8520)
client.connect(ip_port) while 1:
cmd_msg = bytes(input("请输入cmd指令: "),"utf8")
client.send(cmd_msg)
recv_msg_len = int(str(client.recv(1024),"utf8"))
print(recv_msg_len)
has_recv = bytes() # 接收到总的字节流长度
while len(has_recv) < recv_msg_len: # 循环接收,直到字节流的长度相等
has_recv += client.recv(1024)
print(str(has_recv,"gbk"))
print(len(has_recv))

循环接收方案

    第二种方案: 通过struck模块将需要发送的内容的长度进行打包,打包成一个4字节长度的数据发送到对端,对端只要取出前4个字节,然后对这四个字节的数据进行解包,拿到你要发送的内容的长度,然后通过这个长度来继续接收我们实际要发送的内容(不好理解看代码, 简单)。

 import socket
import subprocess
import struct # 客户端(发送方)
server = socket.socket()
ip_port = ("192.168.12.42",8520)
server.bind(ip_port)
server.listen(4)
conn,addr = server.accept() while 1:
recv_msg = str(conn.recv(1024),"utf8")
cmd_obj = subprocess.Popen(
recv_msg,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
cmd_msg = cmd_obj.stdout.read()
numb_b = struct.pack("i",len(cmd_msg))
conn.send(numb_b + cmd_msg) # 把 总字节流长度 + 字节内容 发给接收方,接收方接收前4个字节拿到总字节长度,
# 然后按照总字节流长度来接收. # 客户端(接收方)
import socket
import struct client = socket.socket()
ip_port = ("192.168.12.42",8520)
client.connect(ip_port) while 1:
cmd_msg = bytes(input("请输入cmd指令: "),"utf8")
client.send(cmd_msg)
numb_b = client.recv(4)
numb_len = struct.unpack("i",numb_b)[0]
msg = client.recv(numb_len)
print(str(msg,"gbk"))

struct方案

python摸爬滚打之day28----黏包处理的更多相关文章

  1. Python学习笔记【第十四篇】:Python网络编程二黏包问题、socketserver、验证合法性

    TCP/IP网络通讯粘包问题 案例:模拟执行shell命令,服务器返回相应的类容.发送指令的客户端容错率暂无考虑,按照正确的指令发送即可. 服务端代码 # -*- coding: utf- -*- # ...

  2. python学习之socket&黏包

    7.4 socket ​ [重要] 避免学习各层的接口,以及协议的使用, socket已经封装好了所有的接口,直接使用这些接口或者方法即可,方便快捷,提升开发效率. socket在python中就是一 ...

  3. Python网络编程之黏包问题

    二.解决黏包问题 2.1 解决黏包方法1 计算消息实体的大小 服务端接受两次,一次时消息大小,二次是消息实体,解决消息实体黏包 客户端发送两次,一次是消息大小,一次是消息实体 在两次收发之间加入一次多 ...

  4. day28 黏包及黏包解决方案

    今日主要内容: 一 .缓冲区 二.两种黏包现象 三.黏包现象的两种解决方案 四.打印进度条(补充的,了解即可) 1. 缓冲区 缓冲区的作用 : 将程序和网络解耦(这样做的好处是程序不会以为网速的快慢而 ...

  5. python socket编程和黏包问题

    一.基于TCP的socket tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端,有顺序,不重复,可靠.不会被加上数据边界. server端 import socket sk = so ...

  6. python 黏包现象及其解决方案

    一.数据缓冲区 缓冲区(buffer),它是内存空间的一部分.也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区,显然缓冲区是具有一定大小的 ...

  7. Python Socket通信黏包问题分析及解决方法

    参考:http://www.cnblogs.com/Eva-J/articles/8244551.html#_label5 1.黏包的表现(以客户端远程操作服务端命令为例) 注:只有在TCP协议通信的 ...

  8. Python 的黏包问题

    Client 端内的代码: #Author:BigBao #Date:2018/7/4 import socket import struct client=socket.socket(socket. ...

  9. 038.Python关于TCP黏包问题

    黏包现象 1 黏包现象演示 服务端 #服务端 import socket sk = socket.socket() # 注册主机到网络 sk.bind( ("127.0.0.1", ...

随机推荐

  1. nmap简介和使用

    文章链接:https://blog.csdn.net/m1585761297/article/details/80015726 参考链接:https://www.cnblogs.com/nmap/p/ ...

  2. iOS 新建xib文件时,最外层view的约束问题

    今天用在利用xib实例化view 时, 生成的view的自动布局总是用问题.具体来说,宽和高都不能和父view正确变化.仔细检查,发现下图: 注意这里右上角的Autoresizing部分,并没有设置正 ...

  3. 修正锚点跳转位置 避免头部fixed固定部分遮挡

    如下锚点标签: <div id="id1"> <span class="kkAnchor"></span> 正文正文正文正文 ...

  4. sort排序用法

    Python] sorted函数 我们需要对List.Dict进行排序,Python提供了两个方法对给定的List L进行排序,方法1.用List的成员函数sort进行排序,在本地进行排序,不返回副本 ...

  5. (七)Knockout 创建自定义绑定

    创建自定义绑定 你可以创建自己的自定义绑定 – 没有必要非要使用内嵌的绑定(像click,value等).你可以你封装复杂的逻辑或行为,自定义很容易使用和重用的绑定.例如,你可以在form表单里自定义 ...

  6. php实现微信企业向用户付款

    <?php header('content-type:text/html;charset=utf-8'); $data['mch_appid']='##################';//商 ...

  7. C++中STL常用容器的优点和缺点

    我们常用到的STL容器有vector.list.deque.map.multimap.set和multiset,它们究竟有何区别,各自的优缺点是什么,为了更好的扬长避短,提高程序性能,在使用之前需要我 ...

  8. 理解上下文Context

    --摘自<Android进阶解密> 知识点: 1.Context的使用场景 1)使用Context调用方法,比如启动Activity.访问资源.调用系统级服务等 2)调用方法时传入Cont ...

  9. 2018山东省赛sequence

    2018山东省赛sequence因为必须要删除一个数,所以可以计算每个数删除的代价,从而选取代价最小的进行删除如果一个数大于它前面的所有数的最小值而小于次小值,删除最小值的代价就要+1:如果一个数本身 ...

  10. weblogic 安装部署详解

    0x01 weblogic下载安装 去Oracle官网下载Weblogic 10.3.6,选择Generic版本,各版本选择下载地址:http://www.oracle.com/technetwork ...