第八章 socket网络编程(7):模拟ssh远程执行命令

接下来我们用之前的知识,模拟一个远程执行命令的小程序

server.py

import socket
import subprocess
import locale

ssh_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 初始化一个socket连接对象
ssh_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

ssh_server.bind(('127.0.0.1', 8080))  # 注意bind只需要一个参数,元组类型
ssh_server.listen(3)

while True:
    conn, addr = ssh_server.accept()
    while True:  # 从这里开始,我们使用的对象就是连接对象conn了
        try:
            # 接收命令字符串
            cmd = conn.recv(1024).decode('utf-8') # 传来的是bytes类型,需要decode
            if not cmd: break
            print("excute cmd:", cmd)
            # 执行命令,拿到结果
            # import os
            # res = os.system(cmd)  # 使用os模块来执行cmd,但是os.system()没有返回值※return 0,这样我们没法返回结果给客户端
            obj = subprocess.Popen(cmd, shell=True,  # 使用subprocess模块可以实现要求
                             stdout=subprocess.PIPE,  # 生成一个管道,用来输出执行的结果
                             stderr=subprocess.PIPE)  # 生成一个管道,用来接收error信息

            stdout = obj.stdout.read()  # 从管道读取执行结果,结果是bytes类型,
            stderr = obj.stderr.read()  # 读取error结果
            # 注意,read()只能读取一次,第二次会取不到内容
            # stdout1 = obj.stdout.read()  # 这个是空的
            # print(stdout1)  # 打印一下看看,结果是 b''

            # 注意,操作系统会用默认的编码来encode(linux:utf-8,windows:因os语言而异),所以print的时候需要注意
            os_locale = locale.getdefaultlocale()  # 我们使用locale模块来获取默认的区域设置并返回元祖(语言, 编码)
            os_encode = os_locale[1]
            # print(locale.getdefaultlocale())  # ('ja_JP', 'cp932')
            print(stdout.decode(os_encode))

            # 把命令结果返回给客户端
            conn.send(stdout+stderr)  # 这个+是个可以优化的点
        except ConnectionResetError as e:
            print(e)
            break
    conn.close()

ssh_server.close()

client.py

import socket

ssh_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

ssh_client.connect(('127.0.0.1', 8080))

while True:
    # 发命令
    cmd = input(">>>>:").strip()
    if not cmd:continue
    ssh_client.send(cmd.encode('utf-8'))
    # 取得返回的结果并打印
    data = ssh_client.recv(1024)  # 1024是一个坑:超过1024字节,解码的时候就会混乱
    print(data)  # 服务器的执行结果是服务器OS用其默认编码来encode的(linux:utf-8,windows:因os语言而异),客户端decode时需注意
    
    # 可能是因为传来的bytes类型不完整,导致没法正确解码,Windows系统下报错了,Linux系统似乎不会报错,但是会粘包
    try:  # 这个异常处理是为了防止,客户端解码失败报错导致强制结束socket连接
        print(data.decode('cp932'))  # 这里知道服务器os的编码是cp932,所以固定写成这个了。如果encode指定错误会报错
    except Exception as e:
        print(e)

ssh_client.close()

猜你喜欢

转载自www.cnblogs.com/py-xiaoqiang/p/11298989.html