Py003-02-03模拟ssh远程登录

模拟ssh远程登录

注意 window默认编码是gbk,linux默认是 utf-8

服务端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import socket
import subprocess

phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8082)) # ip 加端口号
phone.listen(5) # 5代表最大链接数

print('starting....')
while True: # 链接循环
conn,client_addr = phone.accept()

while True: # 通讯循环
try:
# 1 接受命令
cmd = conn.recv(1024)
# 针对客户端中断问题
if not cmd:break # 适用于linux 如果是windows就 try catch
# 2 执行命令,拿到结果
obj = subprocess.Popen(cmd.decode('gbk'),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
stdout = obj.stdout.read().decode('gbk')
stderr = obj.stderr.read().decode('gbk')
# 3 把命令结果返回给客户端
data = stdout+stderr
print(len(data))
conn.send(data.encode('gbk'))
except ConnectionResetError: # 适用于windows
break
conn.close()

phone.close()

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import socket

phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8082)) # ip 加端口号

while True:
# 1 发命令
cmd = input('>>:').strip()
phone.send(cmd.encode('gbk'))
# 2 拿到命令结果
data = phone.recv(1024) # 1024的坑
print(data.decode('gbk'))

phone.close()

1024的坑

如果命令的返回结果超过1024的话,就会有问题了。即——粘包

我们知道结果保存在管道里,你内容超过1024的时候,多余的内容还在管道里

所以当你输入 ipconfig 的时候假设结果为2024 那么还残留1000 在管道里,你再次输入其他命令如ls的时候会先把上次剩余的内容 返回。。。

以上现象就是————————粘包

粘包的原理

1
2
3
4
5
6
7
1. 不管是recv 和send都不是直接接受对方的数据,而是操作自己的操作系统内存---》不是一个send对应一个recv
2. recv:
wait data 耗时时间长
copy data
send:
copy data
3.

粘包的触发条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
客户端
client.send('hello')
client.send('world')

服务端
res1 = conn.recv(1024) # 'helloworld'
res2 = conn.recv(1024) # ''
send间隔比较短,就会触发粘包,合并一次发送到服务端


客户端
client.send('hello')
time.sleep(5)
client.send('world')
服务端
res1 = conn.recv(1024) # 'hello'
res2 = conn.recv(1024) # 5秒后 'world'

send的间隔已经超过一次正常数据接受的时间。会分两次发送


-------------------------------------------------------
客户端
client.send('hello')
time.sleep(5)
client.send('world')
服务端
res1 = conn.recv(1) # 'h'
res2 = conn.recv(1024) # 5秒后 'ellowworld'

服务端粘包:第一次内容过多,会在下次接受多余的