• 大聊Python----通过Socket实现简单的ssh客户端


    光只是简单的发消息、收消息没意思,干点正事,可以做一个极简版的ssh,就是客户端连接上服务器后,让服务器执行命令,并返回结果给客户端。

    #ssh_client.py
    
    import socket
    
    client = socket.socket()  # 生命socket类型 同时 生成socket连接# 对相
    client.connect(('HW-20180425SPSL',6969))  # 连接6969端口
    while True:
        msg = input(">>:").strip()
        if len(msg) == 0:continue
        client.send(msg.encode("utf-8"))
        data = client.recv(512) # 接收到 512 个字节
        print(data.decode())
    
    
    client.close()
    #ssh_server
    
    import socket
    import os
    
    server = socket.socket()
    server.bind(("HW-20180425SPSL",6969)) # 绑定要监听的端口
    server.listen(5) # 监听   最大允许多少监听
    
    while True:  # 大循环
        conn, addr = server.accept()
    
        while True:
            data = conn.recv(1024)
            print(data.decode())
            if not data:
                print("client has lost....")
                break
            print("执行指令",data)
            cmd_res = os.popen(data.decode()).read()   # 接收字符串 执行结果也是字符串
            if len(cmd_res) == 0:
                cmd_res = "cmd has no output..."
            conn.send(cmd_res.encode("utf-8"))
    
    server.close()

    执行dir后,你就会发现执行命令后,返回结果不全!然后再执行pwd,你会发现执行pwd后,会返回dir没有显示的剩余数据!这是为什么呢?

    这是因为,我们的客户写client.recv(512), 即客户端一次最多只接收512个字节,如果服务器端返回的数据是2000字节,那有至少1400多字节是客户端第一次接收不了的,那怎么办呢,服务器端此时不能把数据直接扔了呀,so它会暂时存在服务器的io发送缓冲区里,等客户端下次再接收数据的时候再发送给客户端。 这就是为什么客户端执行第2条命令时,却接收到了第一条命令的结果的原因。 这时有同学说了, 那我直接在客户端把client.recv(1024)改大一点不就好了么, 改成一次接收个100mb,哈哈,这是不行的,因为socket每次接收和发送都有最大数据量限制的,毕竟网络带宽也是有限的呀,不能一次发太多,发送的数据最大量的限制就是缓冲区能缓存的数据的最大量,这个缓冲区的最大值在不同的系统上是不一样的, 我实在查不到一个具体的数字,但测试的结果是,在linux上最大一次可接收10mb左右的数据,不过官方的建议是不超过8k,也就是8192,并且数据要可以被2整除,不要问为什么 。anyway , 如果一次只能接收最多不超过8192的数据 ,那服务端返回的数据超过了这个数字怎么办呢?比如让服务器端打开一个5mb的文件并返回,客户端怎么才能完整的接受到呢?那就只能循环收取啦。 

    ## ssh_client ##
    
    import socket
    
    client = socket.socket()  # 生命socket类型 同时 生成socket连接# 对相
    client.connect(('HW-20180425SPSL',6969))  # 连接6969端口
    while True:
        msg = input(">>:").strip()
        if len(msg) == 0:continue  # 为空继续
        client.send(msg.encode("utf-8")) # 将 字符串 进行编码 发送给 服务器端
        data_size = client.recv(512)  # 接收 服务端向客户端 发送的 cmd 操作命令后生成的数据的长度
        print("命令的长度为:",data_size) # unicode
        reserver_size = 0
        while reserver_size < int(data_size.decode()):  # 0 < 512
            data = client.recv(512)           # 循环第一次 len(data) = 512 , 循环第二次 len(data) = 201
            reserver_size += len(data)  # 每次收到有可能小于512 ,所以必须用len()判断
            print(reserver_size) # 循环第一次 len(reserver_size) = 512  , 循环第二次 len(reserver_size) = 713
            print(data.decode())
        else: # 数据发送完毕
            print("data res receive down...",reserver_size)
    
    client.close()
    ## ssh_server.py ##
    
    import socket
    import os
    
    server = socket.socket()
    server.bind(("HW-20180425SPSL",6969)) # 绑定要监听的端口
    server.listen(5) # 监听   最大允许多少监听
    
    while True:  # 大循环
        conn, addr = server.accept()
    
        while True:
            data = conn.recv(512)   # 客户端 向 服务端 发送过来的数据(也就是字符串)
            print(data.decode())    #  将该字符串进行解码 打印该字符串
            if not data:           # 数据为空
                print("client has lost....")
                break
            print("执行指令",data)       # unicode
            cmd_res = os.popen(data.decode()).read()   # 接收cmd的字符串 执行结果也是字符串
            if len(cmd_res) == 0:  # cmd 发送过来的 数据长度为0
                cmd_res = "cmd has no output..."
            conn.send(  str(len(cmd_res.encode())  ).encode("utf-8")  )  #先发大小给客户端 因为 len(cmd_res)结果是整数,所以 需要将它变为字符串 ,因为只有字符串才可以encode
            conn.send(cmd_res.encode("utf-8"))
    
    server.close()

    ssh_server所显示出来的结果为:

    dir
    执行指令 b'dir'

    ssh_client所显示出来的结果为:

    >>:dir
    命令的长度为: b'713'
    512
    驱动器 E 中的卷是 Lunix
    卷的序列号是 561D-6560

    E:week_27_1 的目录

    2018/07/03 20:30 <DIR> .
    2018/07/03 20:30 <DIR> ..
    2018/07/03 20:34 <DIR> .idea
    2018/06/19 18:45 <DIR> app01
    2018/07/03 20:30 1,070 client.py
    2018/06/14 09:45 556 manage.py
    2018/07/03 20:18 1,094 server.py
    2018/06/14 09:48 <DIR> static
    2018/06/19 15:53 <DIR> templates
    2018/07/01 15:41 62
    713
    text.text
    2018/06/14 09:44 <DIR> venv
    2018/06/19 15:26 <DIR> week_27_1
    4 个文件 2,782 字节
    8 个目录 22,906,576,896 可用字节

    data res receive down... 713

  • 相关阅读:
    centos7.5搭建zabbix3.4.x以及mysql定制化监控
    dockerfile 的常用讲解
    使用nginx快速搭建文件服务器
    centos7 安装ELK
    centos7 安装Gitlab
    centos7 安装jenkins
    ansible-playbook使用详解
    DNS主从配置
    ansible 安装部署文档
    WPF Grid MouseWheel事件无法触发
  • 原文地址:https://www.cnblogs.com/zhuifeng-mayi/p/9259376.html
Copyright © 2020-2023  润新知