在socket的模块可以发送数据消息的基础上,我们想远程发送一些系统命令来远程调试服务器。执行系统命令的模块一开始可能给会想到os模块,如下:
import os
res= os.system("dir")
print("命令的结果:",res)
'''
Windows操作系统的的常用命令:
dir\ :查看某一个文件夹下的子文件名与子文件夹名
ipconfig: 查看本地网卡的ip地址
tasklist :查看运行的进程
'''
输出结果如下:
这里显示乱码,因为windows系统上文件都为
gbk
,但是pycharm
上的Global Encoding
为utf-8
,所以乱码。
我们在这里看到把res取出来结果为0,这个0是来判断命令是否执行。0代表执行,非0的数字代表执行错误。
开发一个远程执行命令的软件,服务端必须满足至少三点:
所以,OS模块根本拿不到我们想要的结果。
xshell
远程执行命令的实现在这里,我们引入可以用subprocess
模块来实现。
subprocess模块定义了一个类: Popen
class subprocess.Popen( args,
bufsize = 0,
executable = None,
stdin = None,
stdout = None,
stderr = None,
preexec_fn = None,
close_fds = False,
shell = False,
cwd = None,
env = None,
universal_newlines = False,
startupinfo = None,
creationflags = 0)
args
:args
参数。可以是一个字符串,可以是一个包含程序参数的列表。要执行的程序一般就是这个列表的第一项,或者是字符串本身。shell=True
:在Linux下,当shell=True时,如果arg是个字符串,就使用shell来解释执行这个字符串。如果args是个列表,则第一项被视为命令,其余的都视为是给shell本身的参数。也就是说,等效于:subprocess.Popen(['/bin/sh', '-c', args[0], args[1], ...])
stdin stdout和stderr
:stdin stdout和stderr,分别表示子程序的标准输入、标准输出和标准错误。可选的值有PIPE或者一个有效的文件描述符(其实是个正整数)或者一个文件对象,还有None。如果是PIPE,则表示需要创建一个新的管道,如果是None,不会做任何重定向工作,子进程的文件描述符会继承父进程的。另外,stderr的值还可以是STDOUT,表示子进程的标准错误也输出到标准输出。介绍完以上,我们就开始基于socket和subprocess动手写代码了。
from socket import *
import subprocess # 允许我们启动一个新进程,并连接到它们的输入/输出/管道,从而获取返回值
server = socket(AF_INET,SOCK_STREAM)
server.bind(("127.0.0.1",9903))
server.listen(5)
while True: #连接循环
print("Waiting for connection...")
conn,addr = server.accept()
print(f"来自{addr}的连接")
while True: #循环通讯
try:
cmd = conn.recv(1024)
# 运行系统命令
if not cmd:
'''
这里解决的问题是:
1.当你的程序在linux系统中,客户端强制断开连接,服务端会会收到空数据,在这种情况下就会退出与当前客户端的通讯循环,
并关闭与该客户端的连接, 并回收当前客户端在服务端当前所占的系统资源。
2.还有另一种情况就是客户端正常使用close()断开连接, 服务端也会收到空的数据。
'''
break
# 创建管道,执行命令、拿到结果
obj=subprocess.Popen(
cmd.decode("utf-8"), #输入cmd命令
shell=True, #通过shell运行
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
res1=obj.stdout.read() #从正确输出管道中读数据
res2 = obj.stderr.read() # 从错误输出管道中读数据
conn.send(res1+res2) #返回命令执行的结果
except Exception:
'''
这里解决的问题是:
1.当你的程序运行在windows系统中,客户端强制断开链接,服务端就会引发异常. 因此,就可以使用异常处理机制来监测这种异常,
此时一旦监测出这种异常,就代表客户端强制断开了链接.
2.在这种情况下就会退出与当前客户端的通讯循环,并关闭与该客户端的连接, 并回收当前客户端在服务端当前所占的系统资源,
'''
break
conn.close()
server.close()
from socket import *
client = socket(AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1', 9903))
while True:
cmd = input('请输入命令>>').strip()
if not cmd:
'''
# 这里解决的问题,当客户端输入为空的时候,在客户端的操作系统缓存中,并没有数据能发送给服务端. 硬件不能识别你这个空的数据,只有我们这种逻辑层面才有这种空的数据的存在.
# 因此服务端的recv操作会在服务端的操作缓存中拿取数据,但是与此同时,服务端的操作系统缓存中并没有数据,于是服务端一直在recv堵塞状态.
# 接着客户端因为send发送了数据,处于recv等待服务端发送回来的数据的状态,因而两者会处于一种recv堵塞的状态,
'''
continue
client.send(cmd.encode("utf-8"))
res=client.recv(1024) #发送内容大于1024会出现粘包
print(res.decode('gbk')) #注意如果是linux系统,字符编码应该改为utf-8,否则报错:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb2 in position 5: invalid start byte
输出结果如下:
输入dir
命令,由于服务端发送字节少于1024字节,客户端可以接受。
输入tasklist
命令,由于服务端发送字节多于1024字节,客户端只接受部分数据,并且当你再次输入dir
命令的时候,客户端会接收dir
命令的结果,但是会打印上一次的剩余未发送完的数据,会出现粘包问题
针对以上问题:,我们可以在客户端调高最大接收量, 但这并不是我们的解决方案, 于是我们就可以对接收的字节进行循环接收, 直到接收完为止,如下:
from socket import *
client = socket(AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1', 9903))
while True:
cmd = input('请输入命令>>').strip()
if not cmd:
'''
# 这里解决的问题,当客户端输入为空的时候,在客户端的操作系统缓存中,并没有数据能发送给服务端. 硬件不能识别你这个空的数据,只有我们这种逻辑层面才有这种空的数据的存在.
# 因此服务端的recv操作会在服务端的操作缓存中拿取数据,但是与此同时,服务端的操作系统缓存中并没有数据,于是服务端一直在recv堵塞状态.
# 接着客户端因为send发送了数据,处于recv等待服务端发送回来的数据的状态,因而两者会处于一种recv堵塞的状态,
'''
continue
client.send(cmd.encode("utf-8"))
while True:
res=client.recv(1024) #发送内容大于1024会出现粘包
print(res.decode('gbk')) #注意如果是linux系统,字符编码应该改为utf-8
if len(res)< 1024 :break
输出结果如下:
最后附赠宝典,cmd命令锦集,如下
CMD命令锦集
1. gpedit.msc-----组策略
2. sndrec32-------录音机
3. Nslookup-------IP地址侦测器 ,是一个 监测网络中 DNS 服务器是否能正确实现域名解析的命令行工具。 它在 Windows NT/2000/XP 中均可使用 , 但在 Windows 98 中却没有集成这一个工具。
4. explorer-------打开资源管理器
5. logoff---------注销命令
6. shutdown-------60秒倒计时关机命令
7. lusrmgr.msc----本机用户和组
8. services.msc---本地服务设置
9. oobe/msoobe /a----检查XP是否激活
10. notepad--------打开记事本
11. cleanmgr-------垃圾整理
12. net start messenger----开始信使服务
13. compmgmt.msc---计算机管理
14. net stop messenger-----停止信使服务
15. conf-----------启动netmeeting
16. dvdplay--------DVD播放器
17. charmap--------启动字符映射表
18. diskmgmt.msc---磁盘管理实用程序
19. calc-----------启动计算器
20. dfrg.msc-------磁盘碎片整理程序
21. chkdsk.exe-----Chkdsk磁盘检查
22. devmgmt.msc--- 设备管理器
23. regsvr32 /u *.dll----停止dll文件运行
24. drwtsn32------ 系统医生
25. rononce -p----15秒关机
26. dxdiag---------检查DirectX信息
27. regedt32-------注册表编辑器
28. Msconfig.exe---系统配置实用程序
29. rsop.msc-------组策略结果集
30. mem.exe--------显示内存使用情况
31. regedit.exe----注册表
32. winchat--------XP自带局域网聊天
33. progman--------程序管理器
34. winmsd---------系统信息
35. perfmon.msc----计算机性能监测程序
36. winver---------检查Windows版本
37. sfc /scannow-----扫描错误并复原
38. taskmgr-----任务管理器(2000/xp/2003
40. wmimgmt.msc----打开windows管理体系结构(WMI)
41. wupdmgr--------windows更新程序
42. wscript--------windows脚本宿主设置
43. write----------写字板
45. wiaacmgr-------扫描仪和照相机向导
46. winchat--------XP自带局域网聊天
49. mplayer2-------简易widnows media player
50. mspaint--------画图板
51. mstsc----------远程桌面连接
53. magnify--------放大镜实用程序
54. mmc------------打开控制台
55. mobsync--------同步命令
57. iexpress-------木马捆绑工具,系统自带
58. fsmgmt.msc-----共享文件夹管理器
59. utilman--------辅助工具管理器
61. dcomcnfg-------打开系统组件服务
62. ddeshare-------打开DDE共享设置
110. osk------------打开屏幕键盘
111. odbcad32-------ODBC数据源管理器
112. oobe/msoobe /a----检查XP是否激活
68. ntbackup-------系统备份和还原
69. narrator-------屏幕“讲述人”
70. ntmsmgr.msc----移动存储管理器
71. ntmsoprq.msc---移动存储管理员操作请求
72. netstat -an----(TC)命令检查接口
73. syncapp--------创建一个公文包
至于粘包问题,后续更新…