• 模拟ssh远程执行命令


    模拟ssh远程执行命令

    实现在客户端输入执行命令后,返回执行命令的信息.如输入dir,显示当前目录下的所有文件和文件夹。

    send与recv对应,不要出现两边都是相同的情况。recv是跟内存要数据,至于数据的来源,你无需考虑。

    struct模块

    import struct
    
    
    # res = 'akdjsladlkjafkldjfgsdafhjksdfhfdgfdsgdfgssgdglkjdfsfdsadkfjlksdjf;klsdkl;fk;lsfdgklj;sfkldgj;kldfg;lfkd;lgk;lsdkfg;lkfd;glskljdklsajkldsa'
    # print('最原始的',len(res))
    
    # 当原始数据特别大的时候 i模式打包不了 需要更换模式?
    # 如果遇到数据量特别大的情况 该如何解决?
    d = {
        'name':'jason',
        'file_size':3455435435345354524534532456546546565466564366463654543453454353455,
        'info':'为大家的骄傲'
    }
    import json
    json_d = json.dumps(d)
    print(len(json_d))  # 147是json串的长度
    
    
    res1 = struct.pack('i',len(json_d))
    print(len(res1))  # 4
    
    res2 = struct.unpack('i',res1)[0]
    print('解包之后的',res2)  # 147是json串的长度
    

    subprocess模块

    import subprocess
    
    cmd = input('cmd>>>:')
    obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    
    print(obj.stdout.read().decode('gbk'))  # 正确命令返回的结果
    print(obj.stderr.read().decode('gbk'))  # 错误命令返回的结果
    
    # subprocess获取到的数据 拿完就没有了 不能重复的拿
    print(obj.stdout.read().decode('gbk'))  # 正确命令返回的结果
    print(obj.stderr.read().decode('gbk'))  # 错误命令返回的结果
    

    粘包问题

    • 只有TCP有粘包现象,UDP永远不会粘包。
    • 所谓的粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。
    • 粘包情况:两个数据非常小,然后间隔时间又短,数据太大,一次性取不完,下一次还会取到这个大数据。

    TCP特点:回将数据量比较小的,并且时间间隔比较短的数据一次性打包发送给对方。

    客户端

    import socket
    
    
    client = socket.socket()
    client.connect(('127.0.0.1',8081))
    
    client.send(b'hello')
    client.send(b'hello')
    client.send(b'hello')
    

    服务端

    import socket
    
    server = socket.socket()
    server.bind(('127.0.0.1',8081))
    server.listen(5)
    
    conn,addr = server.accept()
    data = conn.recv(100)  # 结束到100个字节的信息
    print(data)
    data = conn.recv(5)
    print(data)
    data = conn.recv(5)
    print(data)
    

    解决粘包问题

    解决粘包问题的原理:在传数据之前,数据的大小必须得定长。

    服务端

    ​ 1.先制作一个发送给客户端的字典

    ​ 2.制作字典的报头

    ​ json序列化

    ​ 编码 统计长度

    ​ 3.发送字典的报头

    ​ 4.发送字典

    ​ 5.再发真实数据

    客户端

    ​ 1.先接受固定长度的4个字节字典的报头

    ​ 2.解析获取到的字典的数据长度

    ​ unpack(...)[0]

    ​ 3.接受字典

    ​ 解码 反序列化

    ​ 4.从字典中获取真实数据的长度

    ​ 5.接受真实数据

    ps:为什么要多加一个字典

    ​ 1.打包的数据大小有限

    ​ 2.可以携带更多的信息

    服务端

    import socket
    import subprocess
    import struct
    import json
    
    
    server = socket.socket()
    server.bind(('127.0.0.1',8080))
    server.listen(5)
    
    
    while True:
        conn, addr = server.accept()
        while True:
            try:
                cmd = conn.recv(1024)
                if len(cmd) == 0:break
                cmd = cmd.decode('utf-8')
                obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)  # 取出的数据为二进制数据
                res = obj.stdout.read() + obj.stderr.read()
                # len(res) 真实数据二进制的长度
                d = {'name':'jason','file_size':len(res),'info':'asdhjkshasdad'}
                json_d = json.dumps(d)  # 把字典保存成json串
                # 1.先制作一个json字符串的报头   报头为4个字节
                header = struct.pack('i',len(json_d))  # 将json字符串的长度打包成4个固定字节
                # 2.发送json字符串报头
                conn.send(header)  # 4 因为i = 4表示的是字节
                # 3.发送json字符串
                conn.send(json_d.encode('utf-8'))  # json字符串编码成2进制传出去
                # 4.再发真实数据
                conn.send(res)  # 直接传二进制数据
                # conn.send(obj.stdout.read())
                # conn.send(obj.stderr.read())
            except ConnectionResetError:
                break
        conn.close()
    

    客户端

    import socket
    import struct
    import json
    
    client = socket.socket()
    client.connect(('127.0.0.1',8080))
    
    while True:
        msg = input('>>>:').encode('utf-8')
        if len(msg) == 0:continue
        client.send(msg)  # 发送命令
        # 1.先接受json字符串报头
        header_dict = client.recv(4)
        # 2.解析报头 获取json字符串的长度
        dict_size = struct.unpack('i',header_dict)[0]  # 解包的时候一定要加上索引0
        # 3.接收json字符串数据
        dict_bytes = client.recv(dict_size)
        # 反序列化json字符串 将json字符串变成字典
        dict_json = json.loads(dict_bytes.decode('utf-8'))
        # 4.从字典中获取信息
        print(dict_json)  # {'name':'jason','file_size':len(res),'info':'asdhjkshasdad'}
        recv_size = 0
        real_data = b''
        while recv_size < dict_json.get('file_size'):  # real_size = 102400 
            data = client.recv(1024)  # 每次获取1024bit数据
            real_data += data  # 数据累加
            recv_size += len(data)  # 目标长度加上获取到的数据的字符串长度
        print(real_data.decode('gbk'))  # 最后打印出所有数据
    

    为何TCP是可靠传输,UDP是不可靠传输

    • TCP在数据传输时,发送端先把数据发送到自己的缓存中,然后协议控制将缓存中的数据发往对端,对端返回一个ack=1,发送端则清理缓存中的数据,对端返回ack=0,则重新发送数据。所以TCP是可靠的。
    • UDP发送数据,对端是不会返回确认消息的,因此不可靠。
  • 相关阅读:
    SQLServer中重建聚集索引之后会影响到非聚集索引的索引碎片吗
    设计表的时候,对于自增列做物理主键使用的一点思考
    MySQL慢查询日志相关的配置和使用。
    Python文件操作---合并文本文件内容
    浅析SQL Server在可序列化隔离级别下,防止幻读的范围锁的锁定问题
    从一个简单的约束看规范性的SQL脚本对数据库运维的影响
    (译)内存沉思:多个名称相关的神秘的SQL Server内存消耗者。
    初试Python语法小试牛刀之冒泡排序
    浅析MySQL中的Index Condition Pushdown (ICP 索引条件下推)和Multi-Range Read(MRR 索引多范围查找)查询优化
    MySQL执行计划extra中的using index 和 using where using index 的区别
  • 原文地址:https://www.cnblogs.com/zuihoudebieli/p/11331782.html
Copyright © 2020-2023  润新知