模擬遠程SSH執行命令的編解碼說明
模擬一個SSH“遠程”執行命令並獲取命令結果的一個程序:
1、在C/S架構下,當客戶端與服務器建立連接(這裏以TCP為例)後,二者可以不斷的進行數據交互。SSH遠程可以實現的效果是客戶端輸入命令可以在服務器中執行並且可以將結果返回給客戶端。但是需要註意的一點事:客戶端的“命令”在計算機看來僅僅是“字符串”而已,而真正需要執行的“命令”必須是操作系統能夠識別的!也就是說,真正“執行命令”與“返回結果”的地方仍然是服務器端。在客戶端我們只是“顯示”出了一個這樣的知執行假象而已。
那麽,這樣的一個SSH遠程執行程序的具體流程是怎樣的呢?
下圖是這樣的一個簡單過程:
簡單的過程說明:
對於客戶端來講,用戶首先輸入了str類型的命令command,然後程序將這個str類型的字符串encode成能夠在網絡中傳輸的bytes類型的數據並發送給服務器;服務器接收到以後將其重新解碼為str,然後在本段“執行”這段代碼生成str類型的結果,接著再進行編碼傳給客戶端,客戶端接收到以後解碼為人能識別的str類型最終輸出到屏幕上。
2、這個過程有兩個大問題:一個是服務器端是如何進行“代碼執行”的,另一個就是客戶端與服務器端str與bytes格式數據的編解碼問題。
2.1、對於第一個問題,我們利用subprocess模塊下的Popen方法可以將str類型的“虛假命令”轉換為操作系統能夠識別的“真是命令”:
import subprocess cmd = input(‘>>>:‘) obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) print(obj.stdout.read().decode(‘gbk‘)) print(obj.stderr.read().decode(‘gbk‘))
這裏有幾點需要說明:
(1)可以把obj看成是一個管道,它一次性的、毫無保留將所有執行結果都拿到,再一次取值時裏面沒有了數據,這就像一個“管道”一樣,裏面的數據全部取完後就“無所保留”了。
(2)關於輸出結果解碼的問題:subprocess模塊下的Popen方法在不同的操作系統下結果的編碼方式不同:linux下為utf-8模式,windows下為gbk模式。由於本例是在windows操作系統下進行的,所以我們在輸出是要進行gbk的方式解碼才能看到結果。
(3)最終的結果包含正確的信息stdout與錯誤的結果stderr(當用戶輸入一個不存在的命令時產生)。
2.2、第二個編解碼問題可以看下圖具體的描述:
這裏需要註意的一點是:本例是在windows操作系統下執行的,所以result的編碼方式要以gbk模式進行,這樣才不會在客戶端中產生亂碼。
程序的代碼以及運行結果為:
import socket import subprocess server_whw = socket.socket(socket.AF_INET,socket.SOCK_STREAM) server_whw.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) server_whw.bind((‘127.0.0.1‘,8008)) server_whw.listen(5) print(‘Starting......‘) conn,client_addr = server_whw.accept() while 1: try: cmd = conn.recv(1024) #將從客戶端傳來的命令信息進行處理 obj = subprocess.Popen(cmd.decode(‘utf-8‘),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) #將結果返回給客戶端 stdout = obj.stdout.read().decode(‘gbk‘) stderr = obj.stderr.read().decode(‘gbk‘) std1 = stdout.encode(‘gbk‘) std2 = stderr.encode(‘gbk‘) conn.send(std1+std2)##這裏可以優化 except ConnectionResetError: print(‘連接斷開‘) break conn.close() server_whw.close()Server_ssh
import socket client_whw = socket.socket(socket.AF_INET,socket.SOCK_STREAM) client_whw.connect((‘127.0.0.1‘,8008)) while 1: cmd = input(‘請輸入命令:‘) if not cmd: continue client_whw.send(cmd.encode(‘utf-8‘)) data = client_whw.recv(1024) print(‘命令結果:\n‘,data.decode(‘gbk‘)) # client_whw.close()Client_ssh
程序演示:
當然,最終的結果出現了粘包問題~需要進行進一步的處理??
模擬遠程SSH執行命令的編解碼說明