zoukankan      html  css  js  c++  java
  • day-32网络编程

    一.半连接数

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

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

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

    socket中 listen(半连接最大数)

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

    
    

    二.粘包问题

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

    UDP 用户数据报协议

    粘包 仅发生在TCP协议中

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

    2. 接收端 一次性读取了两次数据的内容 会粘

    3. 接收端 没有接收完整 剩余的内容 和下次发送的粘在一起

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

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

     

     

    解决方案

    #发送端

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

    2.发送长度数据

    3.发送真实数据

    接收端

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

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

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

    案例: 远程CMD程序 
    #    ==================================================客户端
    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()
    服务器
    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()

    自定义报头

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

    报头本质是一个json 数据

    具体过程如下:

    发送端

      1 发送报头长度

      2 发送报头数据 其中包含了文件长度 和其他任意的额外信息

      3 发送文件内容

     

    接收端

      1.接收报头长度

      2.接收报头信息

      3.接收文件内容

    服务器
    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)

    补充:finally异常处理

    无论try报错执行except,还是正常执行,都会走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("文件关了!")
  • 相关阅读:
    jquery插件:web2.0分格的分页脚,可用于ajax无刷新分页
    Application共享数据
    WebClient类
    HttpResponse类
    IEqualityComparer<T>接口
    物理数据库设计 理解浮点数
    Server对象,HttpServerUtility类,获取服务器信息
    Linq to OBJECT之非延时标准查询操作符
    IComparer<T> 接口Linq比较接口
    会话状态Session
  • 原文地址:https://www.cnblogs.com/klw1/p/10946197.html
Copyright © 2011-2022 走看看