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

news/2024/11/9 5:06:31/

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个bytesif 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的错误breakconn.close()
server.close()

客户端代码,client.py

import socketclient = 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系统下,所以用gbkdata = 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个bytesif 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)#在将字符串转换为bytesheader_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的错误breakconn.close()
server.close()

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

import socket
import struct
import jsonclient = 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 + datarecv_size = recv_size + len(data)print(recv_data.decode("gbk"))client.close()

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


http://www.ppmy.cn/news/628720.html

相关文章

记一次docker-compose的坎坷安装经历

最近公司在做一个kafka项目&#xff0c;所以想用docker来安装kafka集群&#xff0c;所以安装完docker后就准备安装docker-compose&#xff0c;但在安装过程中确碰到了各种问题&#xff0c;搞了两个半天再通过翻墙工具才终于搞定。 首先看了篇文章显示安装前要对应docker版本。 …

代码随想录算法训练营第五十天|123.买卖股票的最佳时机III、188.买卖股票的最佳时机IV

买卖股票的最佳时机III 题目链接&#xff1a;力扣 和昨天两道题相比&#xff0c;此题关键在于至多买卖两次 这意味着可以买卖一次&#xff0c;可以买卖两次&#xff0c;也可以不买卖。 确定dp数组以及下标的含义 一天一共就有五个状态&#xff0c; 没有操作 第一次持有股票…

2023年的数据泄露报告显示:人为因素成主要威胁

2023年的数据泄露报告统计数据表明&#xff0c;人的因素是数据泄露的主要威胁。 攻击者们大量利用被盗凭据、特权滥用、人为错误、精心策划的社会工程学攻击、商业电子邮件欺诈(BEC)&#xff0c;开展攻击活动。因此企业不能仅依靠员工安全意识培训作为唯一管理手段&#xff0c…

dlink

DBLINK详解 1.创建dblink语法&#xff1a; CREATE [PUBLIC] DATABASE LINK link CONNECT TO username IDENTIFIED BY password USING ‘connectstring’ 说明&#xff1a; 1) 权限&#xff1a;创建 数据库链接的帐号必须有CREATE DATABASE LINK或CREATE PUBLIC DATABASE LINK的…

flink sql 知其所以然(十六):flink sql 开发企业级利器之 Dlink

1.序篇 博主这个系列都是讲 flink sql 相关的实践的。 讲到这个章节&#xff0c;其实挺多常用的 flink sql 语法及实战案例都已经讲了。 那么原理讲了&#xff0c;得在自己家公司把 flink sql 这等好东西用起来啊。 搞大数据开发的同学基本都知道在 HUE 上面写 hive sql 贼…

C++ Primer Plus笔记: 2023.06.28

1.对数组应用sizeof运算符后得到的是数组的长度&#xff0c;而对指针应用sizeof得到的是指针的长度&#xff0c;即使指针指向的是一个数组。在这种情况下&#xff0c;C不会将数组名解释为地址。 2.数组名被解释为第一个元素的地址&#xff0c;而对数组名应用地址运算符时&…

C++关闭桌面

C关闭桌面,explorer.exe #include<Windows.h> #include <TlHelp32.h> #include"resource.h" #pragma warning(disable:4996) void taskkill(const char * name) {HANDLE info_handle CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //拍摄系统中所…

带控制面板英伟达驱动下载地址

原理&#xff1a;去掉官方原有下载地址里面的DCH&#xff0c;451.67对应你要下载驱动的版本号可以修改 https://cn.download.nvidia.cn/Windows/451.67/451.67-desktop-win10-64bit-international-whql.exe https://cn.download.nvidia.cn/Windows/451.67/451.67-desktop-win10…