首页 > 编程语言 >python网络编程(二)模拟ssh远程执行命令

python网络编程(二)模拟ssh远程执行命令

时间:2024-01-31 15:56:32浏览次数:43  
标签:执行命令 socket python server header client ssh recv 客户端

1、项目需求:

要实现一个像ssh远程连接工具一样,在终端输入命令,返回对应的结果。
比如window的dos命令
dir :查看目录下的文件
ipconfig : 查看网卡信息
tasklist : 查看进程列表
linux的命令:
ls : 查看目录下的文件
ifconfig : 查看网卡信息
ps -aux : 查看进程列表

2、项目分析:

这就是一个典型的c/s模式,在客户端发送一个命令,服务端接收到命令后,执行命令,并获取到执行的结果,再发送给客户端。
那么如何执行命令呢,python中提供了os模块的system可以执行系统命令

import os
res = os.system('dir')
print(res)
 

运行结果:
在这里插入图片描述
os.system()获取的结果只是打印出来了,通过变量去获取打印出来是0,通过这样无法获取。
还有一个比os.system()模块更好的subprocess模块,他更安全,还带有管道。

3、代码实现

服务端代码,server.py

#--coding:utf-8--

import socket
import subprocess
'''
socket.AF_INET:表示是基于网络的套接字家族
socket.SOCK_STREAM:表示流式模块,基于tcp协议
'''
#创建套接字
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
server.bind(('0.0.0.0',8000))
#监听
server.listen()

print('staring....')
while True:  #连接循环
    conn , addr = server.accept()
    print(addr)

    while True:   #通信循环
        try:
            #1、接收命名
            cmd = conn.recv(1024)   #1、单位:bytes 2、最大接收1024个bytes
            if not cmd:break   #适用于linux操作系统,如果客户端断开了连接
            
            #2、执行命令
            obj = subprocess.Popen(cmd.decode('gbk'),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
            stdout = obj.stdout.read()
            stderr = obj.stderr.read()

            #3、把命令结果返回给客户端
            conn.send(stdout+stderr)
        except ConnectionResetError:     #适用于windows系统,如果客户端断开连接,在windows系统就会报ConnectionResetError的错误
            break

    conn.close()
server.close()
 

客户端代码,client.py

import socket

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

#发起连接,服务端的ip和端口
client.connect(('127.0.0.1',8000))

while True:
    cmd = input(">>: ").strip() #去掉空格
    if not cmd:continue      #如果发的是空就进入下一次循环
    client.send(cmd.encode("gbk"))   #因为是在windows系统下,所以用gbk
    data = client.recv(1024)
    print(data.decode("gbk"))

client.close()
 

运行结果:
在这里插入图片描述
可以看到客户端第一次输入ipconfig命令后返回了结果,但是在第二次输入dir 命令后,首先接收的是第一次没有接收完的网卡信息,这是因为客户端接收的数据存放在管道中,一次最大只能接收1024个字节,超出的部分依然保留在管道里面,下次再接收数据的时候,会先把积压的数据给取出来,再取后面的。这种现象就是粘包现象。还有如果发送端多次发送数据量小且间隔时间短也会出现粘包问题。

  1. TCP (transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务。收发两端(客户端和服务器端)都要有一- -成对的socket,因此,发送端为了将多个发往接收端的包,更有
    效的发到对方,使用了优化方法(Nagle算法) ,将多次间隔较小且数据量小的数据,合并成一 个大的
    数据块,然后进行封包。这样,接收端,就难于分辨出来了,必须提供科学的拆包机制。即面向流的通信是无消息保护边界的。
    2. UDP (user datagram protocol,用户数据报协议)是无连接的,面向消息的,提供高效率服务。不会
    使用块的合并优化算法,,由于UDP支持的是- -对多的模式,所以接收端的skbuff(套接字缓冲区)采用
    了链式结构来记录每一个到达的UDP包, 在每个UDP包中就有了消息头(消息来源地址,端口等信
    息),这样,对于接收端来说,就容易进行区分处理了。即面向消息的通信是有消息保护边界的。
    3. tcp是基于数据流的,于是收发的消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住,而udp是基于数据报的,即便是你输入的是空内容(直接回车),那也不是空消息,
    udp协议会帮你封装.上消息头,实验略

如何解决粘包问题

目前的问题就是客户端只接收了一次数据,数据量大的时候没有接收完,如果我们知道这个数据的大小就可以通过循环来把所有的数据都读取出来了。
那么服务端在发送命令结果前要先把结果大小先传给客户端,可以在数据包的前面加一个数据报的头,这个头是一个固定大小的字节。这个头可以用一个字典来处理。

服务端改善的代码如下,文件名server.py

#--coding:utf-8--

import socket
import subprocess
import struct
import json
import threading

#创建套接字
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
server.bind(('0.0.0.0',8000))
#监听
server.listen()

print('staring....')
while True:  #连接循环
    conn , addr = server.accept()
    print(addr)

    while True:   #通信循环
        try:
            #1、接收命名
            cmd = conn.recv(2048)   #1、单位:bytes 2、最大接收1024个bytes
            if not cmd:break   #适用于linux操作系统,如果客户端断开了连接
            
            #2、执行命令
            obj = subprocess.Popen(cmd.decode('gbk'),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
            stdout = obj.stdout.read()
            stderr = obj.stderr.read()

            #3、把命令结果返回给客户端
            #第一步制作固定长度的包头
            header_dic = {
                'filename':'a.txt',
                'md5':'********',
                'total_size': len(stdout)+len(stderr)
            }
            #将字典转化成字符串
            header_json = json.dumps(header_dic)
            #在将字符串转换为bytes
            header_bytes = header_json.encode("gbk")
            #第二步,先发送包头的长度
            conn.send(struct.pack('i',len(header_bytes)))
            #第三步: 发送报头
            conn.send(header_bytes)
            #第四步:再发送真实的数据
            conn.send(stdout)
            conn.send(stderr)
        except ConnectionResetError:     #适用于windows系统,如果客户端断开连接,在windows系统就会报ConnectionResetError的错误
            break

    conn.close()
server.close()
 

完善后的客户端代码,文件名client.py

import socket
import struct
import json

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

#发起连接,服务端的ip和端口
client.connect(('127.0.0.1',8000))

while True:
    cmd = input(">>: ").strip() #去掉空格
    if not cmd:continue      #如果发的是空就进入下一次循环
    #1、发送命令
    client.send(cmd.encode("gbk"))

    #2、拿命令的结果并打印
    #第一步:接收报头的长度
    obj = client.recv(4)
    header_size = struct.unpack('i',obj)[0]

    #第二步:再收报头
    header_bytes = client.recv(header_size)
    #第三步:从包头中解析出真实数据的描述信息
    header_json = header_bytes.decode("gbk")
    header_dic = json.loads(header_json)

    #一次不能把内容接收完,那就循环接收,只要知道这个内容的总共大小
    total_size = header_dic['total_size']

    #接收真实的数据
    recv_size = 0     #接收的数据大小
    recv_data = b''    #接收的数据
    while recv_size < total_size:
        data = client.recv(1024)
        recv_data = recv_data + data
        recv_size = recv_size + len(data)
    print(recv_data.decode("gbk"))

client.close()
 

运行结果:
在这里插入图片描述
现在就可以一次显示完整了

 

2024-01-31 15:49:55【出处】:https://blog.csdn.net/javascript_good/article/details/131443108

=======================================================================================

标签:执行命令,socket,python,server,header,client,ssh,recv,客户端
From: https://www.cnblogs.com/mq0036/p/17999433

相关文章

  • python网络编程(三)实现文件下载功能
    一:目标:要实现一个客户端从服务端下载文件的功能,这个在模拟ssh远程执行命令的基础上再做修改就可以了二:分析:1、要规定客户端获取文件的格式:下载文件用get文件名,比如要下载服务端的a.txt,就写成geta.txt2、因为我目前是客户端和服务端都是在一台服务器上,我模拟的时候就把......
  • python网络编程(四)用面向对象方式实现文件上传下载
    一:背景在之前已经实现了文件的下载,现在再来完善上传功能,并且使用面向对象来封装,让代码看起来更加清楚明了。二:使用规则和运行结果下载文件,下载格式get文件名get空格后面直接接文件名称,在服务端存放的文件名上传文件,上传格式put文件路径+文件名因为是上传,上传的时......
  • python将pdf每页截图保存
    python将pdf每页保存成图片保存一、安装依赖包pipinstallpdf2image 二、代码importosfrompdf2imageimportconvert_from_pathdefconvert_pdf_to_images(pdf_file,output_folder):#创建输出文件夹os.makedirs(output_folder,exist_ok=True)#......
  • python识别图片中的文本保存到word中
    python可以使用第三方库pytesseract实现图像的文本识别,并将识别的结果保存到word中,代码本生不复杂pytesseract环境有点麻烦这里整理总结一下一、简介Tesseract是一个由HP实验室开发由Google维护的开源的光学字符识别(OCR)引擎,可以在Apache2.0许可下获得。它可以直接使用,或者(......
  • python中设置cudnn作用理解
     1、cudnn的简介cuDNN(CUDADeepNeuralNetworklibrary):是NVIDIA打造的针对深度神经网络的加速库,是一个用于深层神经网络的GPU加速库。如果你要用GPU训练模型,cuDNN不是必须的,但是一般会采用这个加速库。2、torch.backends.cudnn的理解 cuDNN使用非确定性算法,并且可以使用to......
  • Python+Selenium 自动化测试
    自动化测试是把以人为驱动的测试行为转化成机器执行的一种过程,通常在设计了测试用例并通过评审之后,由测试人员根据测试用例中描述的规程一步步执行测试,得到实际结果与期望结果的比较,再此过程中,为了节省人力,时间或硬件资源,提高测试效率,便引用了自动化测试的概念Selenium:是一套代码......
  • `glob`和`fnmatch`都是Python的内置模块,用于文件名的匹配,但它们的功能和使用场景有所
    `glob`和`fnmatch`都是Python的内置模块,用于文件名的匹配,但它们的功能和使用场景有所不同²。1.**fnmatch**:`fnmatch`模块提供了一种简单的方式来匹配Unixshell风格的模式,如`*.py`,`Dat[0-9]*`,`Dat[!0-9]*`等²。它只是将一个文件名与模式进行比较,返回True或False²。例如,......
  • Python工具箱系列(四十九)
    使用PIL进行图片格式与尺寸转换现实世界中,图片是经常需要处理的二进制文件类型。从计算机发展的历史来看,图片的格式丰富多彩,但大体来说分成两类:•位图格式•矢量格式矢量格式如svg等,能够随意放大缩小而不变形,原因在于矢量格式描述了如何产生图形的方法。而位图格式(例如BMP/JPEG/PN......
  • 解决gpt返回json Python没法解析的情况
    importreimportjsondefreplace_newlines(match):#在匹配的字符串中替换\n和\rreturnmatch.group(0).replace('\n','\\n').replace('\r','\\r')defclean_json_str(json_str:str)->str:""&......
  • Python工具箱系列(四十九)
    使用PIL进行图片格式与尺寸转换现实世界中,图片是经常需要处理的二进制文件类型。从计算机发展的历史来看,图片的格式丰富多彩,但大体来说分成两类:•位图格式•矢量格式矢量格式如svg等,能够随意放大缩小而不变形,原因在于矢量格式描述了如何产生图形的方法。而位图格式(例如BMP/J......