zoukankan      html  css  js  c++  java
  • 32 粘包 文件传输

     一.半连接数:
    import socket

    server=socket.socket()

    server.bind(('127.0.0.1', 1263))

    server.listen()

    server.accept()


    三次握手没有完成 称之为半连接

    原因1 恶意客户端没有返回第三次握手信息

    原因2 服务器没空及时处理你的请求

    socket中 listen(半连接最大数量)
    # 最大半连接数 本质就是一个数组  未完成链接的socket 就会被加入到数组中  ,
    # 每一次执行accept 就会完成一个三次握手 ,如果达到最大限制 额外的客户端将直接被拒绝
    # 我们可以调整内核参数来修改 最大等待时长 如果超时 客户还是没有回复第三次握手信息 就直接删除


    # 二.粘包问题

    TCP流式协议, 数据之间没有分界, 就像水 一杯水和一杯牛奶倒在一起了!

    UDP 用户数据报协议

    粘包 仅发生在TCP协议中

    1. 发送端 发送的数据量小 并且间隔短 会粘

    2. 接收端 一次性读取了两次数据的内容 会粘
    3. 接收端 没有接收完整 剩余的内容 和下次发送的粘在一起

    无论是那种情况,其根本原因在于 接收端不知道数据到底有多少

    解决方案就是 提前告知接收方 数据的长度

    # 解决方案

    先发长度给对方 再发真实数据



    #发送端

    1.使用struct 将真实数据的长度转为固定的字节数据

    2.发送长度数据

    3.发送真实数据
    import socket
    import subprocess
    import struct
    server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    server.bind(("127.0.0.1",1688))
    server.listen()
    # back

    while True:
    # socket,addr一个元组 客户端的ip和port
    client,addr = server.accept()
    print("客户端链接成功!")
    # 循环收发数据
    while True:
    try:
    cmd = smallTool.recv_data(client)
    if not cmd:
    break
    print(cmd)

    p = subprocess.Popen(cmd.decode("utf-8"),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    # 不要先读err错误信息 它会卡主 原因不详 linux不会有问题 tasklist netstat - ano啥的
    data = p.stdout.read()
    err_data = p.stderr.read()

    len_size = len(data) + len(err_data)
    print("服务器返回了: %s " % len_size)

    len_bytes = struct.pack("q",len_size)

    # 在发送真实数据前先发送 长度
    client.send(len_bytes)

    # 返回的结果刚好就是二进制
    # 发送真实数据
    client.send(data + err_data)


    except ConnectionResetError as e:
    print("客户端了挂了!",e)
    break
    client.close()







    接收端

    1.先收长度数据 字节数固定

    2.再收真实数据 真实可能很长 需要循环接收

    """
    客户端输入指令
    服务器接收指令并执行 最后返回执行结果
    """
    import socket

    client = socket.socket()
    try:
    client.connect(("127.0.0.1",1688))
    print("链接成功!")

    while True:
    msg = input("请输入要执行指令:").strip()
    if msg == "q": break
    if not msg: continue
    # 发送指令
    # 先发长度
    len_bytes = struct.pack("q",len(msg.encode("utf-8")))
    client.send(len_bytes)
    # 在发指令
    client.send(msg.encode("utf-8"))

    data = smallTool.recv_data(client)
    print(data.decode("GBK"))

    client.close()
    except ConnectionRefusedError as e:
    print("链接服务器失败了!",e)
    except ConnectionResetError as e:
    print("服务器挂了!", e)
    client.close()


    发送端和接收端必须都处理粘包 才算真正的解决了

    struct pack//unpack
     python中的struct主要是用来处理C结构数据的,读入时先转换为Python的字符串类型,然后再转换为Python的结构化类型,比如元组(tuple)啥的~。一般输入的渠道来源于文件或者网络的二进制流。
    # struct.pack()和struct.unpack()
    # 在转化过程中,主要用到了一个格式化字符串(format strings),用来规定转化的方法和格式。
    # struct.pack(fmt,v1,v2,.....)
    # 将v1,v2等参数的值进行一层包装,包装的方法由fmt指定。被包装的参数必须严格符合fmt。最后返回一个包装后的字符串。
    # struct.unpack(fmt,string)
    # 解包。比如pack打包,然后就可以用unpack解包了。返回一个由解包数据(string)得到的一个元组(tuple), 即使仅有一个数据也会被解包成元组。



    try: excapt: finally:
    f = None
    try:
    f = open(r"今日内容s","rt")
    print( f.read())
    # {}["name"]
    except Exception as e:
    print(e)
    finally: # 最终
    if f:f.close()
    print("文件关了!")



    ## 自定义报头

    当需要在传输数据

    发送端

    1.发送报头长度

    2. 发送报头数据

    3. 发送文件内容



    接收端

    接收报头长度

    接收报头信息

    接收文件内容


  • 相关阅读:
    调试D2JS
    PG 中 JSON 字段的应用
    面试----
    机器学习面试题
    闭包和装饰器
    scss-混合@mixin @include @function
    scss基本使用及操作函数
    常用的scss函数(mixin)
    二叉搜索树基本操作实现
    判断一棵树是否是二叉搜索树
  • 原文地址:https://www.cnblogs.com/komorebi/p/10947003.html
Copyright © 2011-2022 走看看