模擬一個SSH「遠程」執行命令並獲取命令結果的一個程序:linux
一、在C/S架構下,當客戶端與服務器創建鏈接(這裏以TCP爲例)後,兩者能夠不斷的進行數據交互。SSH遠程能夠實現的效果是客戶端輸入命令能夠在服務器中執行而且能夠將結果返回給客戶端。可是須要注意的一點事:客戶端的「命令」在計算機看來僅僅是「字符串」而已,而真正須要執行的「命令」必須是操做系統可以識別的!也就是說,真正「執行命令」與「返回結果」的地方仍然是服務器端。在客戶端咱們只是「顯示」出了一個這樣的知執行假象而已。shell
那麼,這樣的一個SSH遠程執行程序的具體流程是怎樣的呢?windows
下圖是這樣的一個簡單過程:服務器
簡單的過程說明:網絡
對於客戶端來說,用戶首先輸入了str類型的命令command,而後程序將這個str類型的字符串encode成可以在網絡中傳輸的bytes類型的數據併發送給服務器;服務器接收到之後將其從新解碼爲str,而後在本段「執行」這段代碼生成str類型的結果,接着再進行編碼傳給客戶端,客戶端接收到之後解碼爲人能識別的str類型最終輸出到屏幕上。架構
二、這個過程有兩個大問題:一個是服務器端是如何進行「代碼執行」的,另外一個就是客戶端與服務器端str與bytes格式數據的編解碼問題。併發
2.一、對於第一個問題,咱們利用subprocess模塊下的Popen方法能夠將str類型的「虛假命令」轉換爲操做系統可以識別的「真是命令」:ssh
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'))
這裏有幾點須要說明:socket
(1)能夠把obj當作是一個管道,它一次性的、毫無保留將全部執行結果都拿到,再一次取值時裏面沒有了數據,這就像一個「管道」同樣,裏面的數據所有取完後就「無所保留」了。ide
(2)關於輸出結果解碼的問題:subprocess模塊下的Popen方法在不一樣的操做系統下結果的編碼方式不一樣:linux下爲utf-8模式,windows下爲gbk模式。因爲本例是在windows操做系統下進行的,因此咱們在輸出是要進行gbk的方式解碼才能看到結果。
(3)最終的結果包含正確的信息stdout與錯誤的結果stderr(當用戶輸入一個不存在的命令時產生)。
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(8096) #將從客戶端傳來的命令信息進行處理 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) conn.send(std2) except ConnectionResetError: print('鏈接斷開') break conn.close() server_whw.close()
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()
程序演示:
固然,最終的結果出現了粘包問題~須要進行進一步的處理🤗