模拟ssh远程执行命令
模拟ssh远程执行命令
实现在客户端输入执行命令后,返回执行命令的信息.如输入dir,显示当前目录下的所有文件和文件夹。
send与recv对应,不要出现两边都是相同的情况。recv是跟内存要数据,至于数据的来源,你无需考虑。
struct模块
import struct
# res = 'akdjsladlkjafkldjfgsdafhjksdfhfdgfdsgdfgssgdglkjdfsfdsadkfjlksdjf;klsdkl;fk;lsfdgklj;sfkldgj;kldfg;lfkd;lgk;lsdkfg;lkfd;glskljdklsajkldsa'
# print('最原始的',len(res))
# 当原始数据特别大的时候 i模式打包不了 需要更换模式?
# 如果遇到数据量特别大的情况 该如何解决?
d = {
'name':'jason',
'file_size':3455435435345354524534532456546546565466564366463654543453454353455,
'info':'为大家的骄傲'
}
import json
json_d = json.dumps(d)
print(len(json_d)) # 147是json串的长度
res1 = struct.pack('i',len(json_d))
print(len(res1)) # 4
res2 = struct.unpack('i',res1)[0]
print('解包之后的',res2) # 147是json串的长度
subprocess模块
import subprocess
cmd = input('cmd>>>:')
obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
print(obj.stdout.read().decode('gbk')) # 正确命令返回的结果
print(obj.stderr.read().decode('gbk')) # 错误命令返回的结果
# subprocess获取到的数据 拿完就没有了 不能重复的拿
print(obj.stdout.read().decode('gbk')) # 正确命令返回的结果
print(obj.stderr.read().decode('gbk')) # 错误命令返回的结果
粘包问题
- 只有TCP有粘包现象,UDP永远不会粘包。
- 所谓的粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。
- 粘包情况:两个数据非常小,然后间隔时间又短,数据太大,一次性取不完,下一次还会取到这个大数据。
TCP特点:回将数据量比较小的,并且时间间隔比较短的数据一次性打包发送给对方。
客户端
import socket
client = socket.socket()
client.connect(('127.0.0.1',8081))
client.send(b'hello')
client.send(b'hello')
client.send(b'hello')
服务端
import socket
server = socket.socket()
server.bind(('127.0.0.1',8081))
server.listen(5)
conn,addr = server.accept()
data = conn.recv(100) # 结束到100个字节的信息
print(data)
data = conn.recv(5)
print(data)
data = conn.recv(5)
print(data)
解决粘包问题
解决粘包问题的原理:在传数据之前,数据的大小必须得定长。
服务端
1.先制作一个发送给客户端的字典
2.制作字典的报头
json序列化
编码 统计长度
3.发送字典的报头
4.发送字典
5.再发真实数据
客户端
1.先接受固定长度的4个字节字典的报头
2.解析获取到的字典的数据长度
unpack(...)[0]
3.接受字典
解码 反序列化
4.从字典中获取真实数据的长度
5.接受真实数据
ps:为什么要多加一个字典
1.打包的数据大小有限
2.可以携带更多的信息
服务端
import socket
import subprocess
import struct
import json
server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
while True:
conn, addr = server.accept()
while True:
try:
cmd = conn.recv(1024)
if len(cmd) == 0:break
cmd = cmd.decode('utf-8')
obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) # 取出的数据为二进制数据
res = obj.stdout.read() + obj.stderr.read()
# len(res) 真实数据二进制的长度
d = {'name':'jason','file_size':len(res),'info':'asdhjkshasdad'}
json_d = json.dumps(d) # 把字典保存成json串
# 1.先制作一个json字符串的报头 报头为4个字节
header = struct.pack('i',len(json_d)) # 将json字符串的长度打包成4个固定字节
# 2.发送json字符串报头
conn.send(header) # 4 因为i = 4表示的是字节
# 3.发送json字符串
conn.send(json_d.encode('utf-8')) # json字符串编码成2进制传出去
# 4.再发真实数据
conn.send(res) # 直接传二进制数据
# conn.send(obj.stdout.read())
# conn.send(obj.stderr.read())
except ConnectionResetError:
break
conn.close()
客户端
import socket
import struct
import json
client = socket.socket()
client.connect(('127.0.0.1',8080))
while True:
msg = input('>>>:').encode('utf-8')
if len(msg) == 0:continue
client.send(msg) # 发送命令
# 1.先接受json字符串报头
header_dict = client.recv(4)
# 2.解析报头 获取json字符串的长度
dict_size = struct.unpack('i',header_dict)[0] # 解包的时候一定要加上索引0
# 3.接收json字符串数据
dict_bytes = client.recv(dict_size)
# 反序列化json字符串 将json字符串变成字典
dict_json = json.loads(dict_bytes.decode('utf-8'))
# 4.从字典中获取信息
print(dict_json) # {'name':'jason','file_size':len(res),'info':'asdhjkshasdad'}
recv_size = 0
real_data = b''
while recv_size < dict_json.get('file_size'): # real_size = 102400
data = client.recv(1024) # 每次获取1024bit数据
real_data += data # 数据累加
recv_size += len(data) # 目标长度加上获取到的数据的字符串长度
print(real_data.decode('gbk')) # 最后打印出所有数据
为何TCP是可靠传输,UDP是不可靠传输
- TCP在数据传输时,发送端先把数据发送到自己的缓存中,然后协议控制将缓存中的数据发往对端,对端返回一个ack=1,发送端则清理缓存中的数据,对端返回ack=0,则重新发送数据。所以TCP是可靠的。
- UDP发送数据,对端是不会返回确认消息的,因此不可靠。
Never,Never,Never give up.