小白学python---------------网络编程之基于socket模块模拟ssh远程执行命令(tcp协议)

struct模块: 该模块可以把任意的类型(如数字),转成一个固定的bytes


服务端

import subprocess
from socket import *
import struct

HOST = '127.0.0.1'
PORT = 8080
ADDR = (HOST, PORT)
BUFSIZE = 1024

server = socket(AF_INET, SOCK_STREAM)

server.bind(ADDR)

server.listen(5)

while True:
    conn, addr = server.accept()
    print('客户端:', addr)
    while True:
        try:
            cmd = conn.recv(BUFSIZE)
            if len(cmd) == 0: break
            print(cmd.decode('utf-8'))

            obj = subprocess.Popen(cmd.decode('utf-8'), 
                                   shell=True, 
                                   stdout=subprocess.PIPE, 
                                   stderr=subprocess.PIPE)

            stdout = obj.stdout.read()
            stderr = obj.stderr.read()

            # 1.计算出总共需要发送多大的文件,制作报头(固定长度)
            total_size = len(stdout) + len(stderr)
            print(total_size)
            # 2.将total_size做成固定的bytes
            header = struct.pack('i', total_size)  # i==>固定4个字节
            # 3.先发送固定长度的报头
            conn.send(header)
            # 4.再发送真实的数据
            conn.send(stdout)
            conn.send(stderr)
        except ConnectionResetError:
            break

    conn.close()
客户端

import struct
from socket import *

client = socket(AF_INET, SOCK_STREAM)
HOST = '127.0.0.1'
PORT = 8080
ADDR = (HOST, PORT)
BUFSIZE = 1024  # 再大不能超过8096

client.connect(ADDR)
while True:
    cmd = input('>>>:').strip()
    if not cmd: continue
    client.send(cmd.encode('utf-8'))

    res = b''
    recv_size = 0
    # 1.先收固定的长度的报头
    header = client.recv(4)
    # 2.从报头中解析出数据的描述信息,再收真实的数据
    total_size = struct.unpack('i', header)[0] 
    # struct.unpack('i', header)得到的是一个元组
    while recv_size < total_size:
        data = client.recv(BUFSIZE)
        res += data
        recv_size += len(data)
    print(res.decode('gbk'))

猜你喜欢

转载自blog.csdn.net/qq_42721964/article/details/82348056