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

news2024/9/25 13:15:58

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()

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/710048.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Jenkins与CI/CD

简介 CI&#xff08;持续集成&#xff09; Continuous Integration是一种软件开发实践&#xff0c;即团队开发成员经常集成他们的工作&#xff0c;通常每个成员每天至少集成一次&#xff0c;也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建&#xff08;包括编…

Debian 环境使用 docker compose 部署 sentry

Debian 环境使用 docker compose 部署 sentry Sentry 简介什么是 Sentry &#xff1f;Sentry 开发语言及支持的 SDKSentry 功能架构 前置准备条件规格配置说明Dcoker Desktop 安装WSL2/Debian11 环境准备 Sentry 安装步骤docker 部署 sentry 步骤演示过程说明 总结 Sentry 简介…

python机器学习在气象模式订正、短临预报、气候预测等场景的应用

基于机器学习的天河机场物流预测研究 全球经济快速增长的形势下,八大区域性枢纽之一的武汉天河机场的物流需求也在攀升。文章针对天河机场的货邮吞吐量,运用机器学习中的线性回归模型通过Python对其进行需求预测,并用二次指数平滑法与之对比,在平均绝对百分误差比较下得出机器…

需求分析引言:架构漫谈(四)性能专题

前文介绍了非功能性需求里的可靠性和可用性&#xff0c; 本文对非功能性需求里的性能&#xff0c;进行一些详细的说明&#xff0c;和如何度量系统的性能问题。 1、概念 性能通常是指一个软件系统的处理能力和速度&#xff0c;一般通过 延迟 和 吞吐量 这两个指标进行度量。 不…

分布式软件架构——域名解析系统

透明多级分流系统的设计原则 用户在使用信息系统的过程中&#xff0c;请求首先是从浏览器出发&#xff0c;在DNS的指引下找到系统的入口&#xff0c;然后经过了网关、负载均衡器、缓存、服务集群等一系列设施&#xff0c;最后接触到了系统末端存储于数据库服务器中的信息&…

云计算——容器

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​ 目录 前言 一.容器简介 二.主流容器技术 1.docker &#xff08;1&#xff09;容器的组…

HTML5+ Runtime提示

使用的环境 vue-cli框架&#xff0c;Andriod调试、云打包都会出现该弹框 1.我遇到的问题 上述弹框提示&#xff0c;HBuilderX3.8.2 &#xff0c; 手机SDK版本是3.8.4&#xff0c;不匹配 解决目的&#xff1a;需要让两个版本匹配 2. 点击“查看详情”&#xff0c;查看原因 …

JS文件UTF8格式乱码问题

UTF8格式的JS文件在IE中显示乱码问题的解决 这种情况通常是由于JS文件头缺少BOM标志引起的,解决方式: 方法1:用系统自带记事本,另存为 UTF-8,覆盖原文件,会自动加上BOM标志(就是文件开头的EF BB BF 三个字节) 方法2: 用notepad 打开,编码菜单,由UTF8编码改为 UTF8-BOM编码

10-Vue从入门到手撕

什么时候可以开始学习Vue? 学习路线&#xff1a;H5 CSS3 ---> ES6 ---> 网络 ---> 第三方库 ---> 工程化 ---> Vue 不经过前面的铺垫是无法学习vue的&#xff0c;就算学了还得倒回去补知识点 展现Vue Vue源码分析&#xff0c;走进作者的内心世界 …

记录一次对STM32G4串口硬件FIFO的调试

记录一次对STM32G4串口硬件FIFO的调试 前言&#xff1a;通常我们使用串口接收多字节数据会使用中断和DMA两种方式。使用中断方式&#xff0c;每接收到一个字节就会触发一次中断&#xff0c;我们可以在中断函数里将接收到的这一字节保存在内存中然后等待其他程序处理&#xff0c…

麦语言是什么东东?怎么学?

麦语言&#xff08;M Language&#xff09;是一种用于处理数据的编程语言&#xff0c;最初由微软公司开发。它是Power Query&#xff08;数据提取和转换工具&#xff09;和Power BI&#xff08;商业智能工具&#xff09;中的一部分。麦语言支持对各种数据源进行查询、转换和清理…

农业温室大棚数据监控系统的设计与实现

1.引言 农业温室大棚作为现在农业发展的必要条件&#xff0c;将高新技术融入农业温室大棚也愈发的重要&#xff0c;对农业温室大棚数据的监控&#xff0c;将温室大棚智能化。本设计对温室大棚实现远程数据监控&#xff0c;自动化控制&#xff0c;对温室内的环境数据进行巡回检…

解决Springboot在启动时报错:不支持发行版本17

今天在创建新项目时控制台出现如下错误&#xff1a; 最后经过排查发现问题出现如下几点。将以下几点进行修改问题得以解决。 1.将红色箭头地方由17改为11 2.将maven的pom文件中 的javaversion由17改为113.将spingboot的版本调为2.7.5 如果以上还没有解决问题&#xff0c;可以尝…

机器视觉(图像处理)入门金典之图像数字化及处理方法

图像的数字化 一般的图像(模拟图像)不能直接用计算机来处理,必须首先转化为数字图像 把模拟图像分割成一个个称为像素的小区域,每个像素的亮度或灰度值用一个整数表示 数字化的含义: 使模拟图像的灰度、亮度和色彩数据化 图像数字化的步骤: 两个步骤: 1、在空间坐标…

时间序列分解 | Matlab改进的自适应噪声完备集合经验模态分解ICEEMDAN

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 时间序列分解 | Matlab改进的自适应噪声完备集合经验模态分解ICEEMDAN 部分源码 %--------------------

【百日冲大厂】第十九篇,牛客网选择题+编程题汽水瓶+ 查找两个字符串a,b中的最长公共子串(动态规划问题)

前言&#xff1a; 大家好&#xff0c;我是良辰丫&#xff0c;第十九篇,牛客网选择题编程题汽水瓶 查找两个字符串a,b中的最长公共子串(动态规划问题).&#x1f49e;&#x1f49e;&#x1f49e;生活就像一只盲盒&#xff0c;藏着意想不到的辛苦&#xff0c;当然也有万般惊喜的可…

【自动化测试】——Selenium (基于java)

前言 小亭子正在努力的学习编程&#xff0c;接下来将开启软件测试的学习~~ 分享的文章都是学习的笔记和感悟&#xff0c;如有不妥之处希望大佬们批评指正~~ 同时如果本文对你有帮助的话&#xff0c;烦请点赞关注支持一波, 感激不尽~~ 目录 一、认识Selenium 1.什么是自动化测…

原码的表示

原码表示 定点整数源码与定点小数源码 源码表示例题 正数与负数转换直接将高位变为1即可 原码的性质 原码的优缺点 乘除法直接符号位异或&#xff0c;数值相乘除即可加法与减法需要先判断两个数值的大小然后确定符号位

软件开发项目延期就天天加班,你认为有效吗?

目录 一、软件开发项目延期的因素 1.1 客户需求变更 1.2 开发人员变动 1.3 技术瓶颈 1.4 对外沟通问题 二、相应的解决方案 2.1 需求变更管理机制 2.2 公司内部人员培训和团队建设 2.3 技术难题攻关 2.4 优化沟通流程 三、总结 软件开发项目延期时加班并不是一个长期…

C++之std::forward模板函数用法(一百四十四)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…