zoukankan      html  css  js  c++  java
  • 粘包

    1.半连接数:

      定义:三次握手没成功,称之为半连接数

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

         1.2:服务器没空及时处理请求

      注:socket 中 listen(最大最大半连接数)

    2.粘包问题

      定义:因为数据间没有分界,混了分不开了粘包le所以就造成     就像水一样    一杯水 倒入一桶水  

           tcp:流失协议  ,粘包仅发生在tcp协议中         udp:用户数据报协议

      原因:1.1:发送端 发送的数据    量小   间隔短     会粘
         1.2:接收端   一次性读取了两次数据的内容       会粘
         1.3:接收端    没接收完整   剩余内容与下次内容        会粘

         总而言之,其根本原因在于接收端不知道数据到底有多少,不是接多了,就是jieshao接少了

      解决方案:提前告诉接收方  数据的长度

    3.具体解决方案

      原理:先发长度给对方,再发真实数据

      过程:发送端:1.使用struct将真实数据的长度转为固定的字节数据
             2.发送长度数据

             3.发送真实数据

           接收端:1.先收长度数据     字节数固定       8

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

            注:只有发送端与接收端都处理了粘包,才算解决了问题

      eg:远程CDM程序

    #==================================================================服务器
    import socket
    import subprocess
    import struct
    from 二_CMD程序 import  smallTool
    
    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()
    
    #server.close()
    #==================================================================客户端
    import socket
    from 二_CMD程序 import smallTool
    import struct
    
    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()

    4.自定义报头

      定义:当需要在传输数据时传一些额外参数时就需要自定义报头

      本质:报头是一个json数据

      过程:发送端:1.发送抱头长度

             2.发送包头数据        其中包含  文件长度   与其他任意的信息

             3.发送文件内容

         接收端:1.接收抱头长度

             2.接收报头数据         数据可能很长     需要循环接收

             3.接收文件内容

      eg:

    #==================================================================服务器
    import socket import os import
    struct import json """ 客户端接链成功我就给你发个文件过去 固定的文件下载 """ 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("客户端链接成功!") f = None try: path = r"F:2.半链接数.mp4" file_size = os.path.getsize(path) # 我想把文件名发过去 file_info = {"file_name":"半链接数.mp4","file_size":file_size,"md5":"xxxxxxxxx"} json_str = json.dumps(file_info).encode("utf-8") # 发送报头长度 client.send(struct.pack("q",len(json_str))) # 发报头 client.send(json_str) # 发文件了 # 发送文件数据 f = open(path,"rb") # 循环发送文件内容 每次发2048 while True: temp = f.read(2048) if not temp: break client.send(temp) print("文件发送完毕!") except Exception as e: print("出问题了",e) finally: if f:f.close() client.close() # 无论是否抛出异常 文件都要关闭 #server.close() # 用户可以指定要下载什么文件 FTP
    #==================================================================客户端
    """
    客户端输入指令 服务器接收指令并执行 最后返回执行结果 """ import socket import struct import json client = socket.socket() try: client.connect(("127.0.0.1",1688)) print("链接成功!") # 1.先收报头长度 head_size = struct.unpack("q",client.recv(8))[0] # 2.收报头数据 head_str = client.recv(head_size).decode("utf-8") file_info = json.loads(head_str) print("报头数据:",file_info) file_size = file_info.get("file_size") file_name = file_info.get("file_name") # 3.再收文件内容 # 已接收大小 recv_size = 0 buffer_size = 2048 f = open(file_name,"wb") while True: if file_size - recv_size >= buffer_size: temp = client.recv(buffer_size) else: temp = client.recv(file_size - recv_size) f.write(temp) recv_size += len(temp) print("已下载:%s%%" % (recv_size / file_size * 100)) if recv_size == file_size: break f.close() except ConnectionRefusedError as e: print("链接服务器失败了!",e)

    5.不异常处理    finally

      用法:无论try中是否出现异常,都会执行finally中的语句        用于做清理工作

      eg:

    f = None
    try:
        f = open(r"今日内容s","rt")
        print( f.read())
        # {}["name"]
    except Exception as e:
        print(e)
    finally: # 最终
        if f:f.close()
        print("文件关了!")
  • 相关阅读:
    自动化测试selenium教程
    Java开发.gitignore文件包含.iml,.log的看法
    基于接口设计与编程
    搭建大众点评CAT监控平台
    正确的打日志姿势
    【每天一条Linux指令-Day1】kill掉多个mysql的进程
    一道SQL面试题——表行列数据转换(表转置)
    @SuppressWarnings注解用法详解
    Spring IoC的底层技术支持——Java反射机制
    出现java.lang.NoSuchMethodError错误的原因
  • 原文地址:https://www.cnblogs.com/wyf20190411-/p/10945605.html
Copyright © 2011-2022 走看看