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. 发送文件内容



    接收端

    接收报头长度

    接收报头信息

    接收文件内容


  • 相关阅读:
    ios UIWebView截获html并修改便签内容(转载)
    IOS获取系统时间 NSDate
    ios 把毫秒值转换成日期 NSDate
    iOS  如何判断当前网络连接状态  网络是否正常  网络是否可用
    IOS开发 xcode报错之has been modified since the precompiled header was built
    iOS系统下 的手机屏幕尺寸 分辨率 及系统版本 总结
    iOS 切图使用 分辨率 使用 相关总结
    整合最优雅SSM框架:SpringMVC + Spring + MyBatis 基础
    Java面试之PO,VO,TO,QO,BO
    Notes模板说明
  • 原文地址:https://www.cnblogs.com/komorebi/p/10947003.html
Copyright © 2011-2022 走看看