模拟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'
服务端粘包:第一次内容过多,会在下次接受多余的
|