远程执行命令
描述:相当于SSH的实现,client发送命令,server端接收并执行后返回结果给client,使用subprocess模块实
实现过程
1.调用subprocess模块
[root@node2 socket]# cat test.py
#!/usr/local/python3/bin/python3
import subprocess
a=subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE)
print(a)
[root@node2 socket]# python3 test.py
<subprocess.Popen object at 0x7fa5f6cae358>
#对象,subprocess实际是自身开了一个进程,与主进程没关系,它有自己的一块区域,与print(a)类似于并行操作,
结果直接显示在屏幕上,但是同时也保存在它的子进程中,需要把它的结果放在能够传输的主进程中,主要使用
管道stdout来实现,stdout=subprocess.PIPE标准输出通过管道,由子进程转到主进程
client.py remote_command.py server.py test.py
[root@node2 socket]# python3 test.py
<subprocess.Popen object at 0x7fd51f307358> #使用stdout就会有输出,把结果转到主进程
2.再使用主进程调用
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
[root@node2 socket]# cat test.py
#!/usr/local/python3/bin/python3
import subprocess
a=subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE)
print(a.stdout.read())
[root@node2 socket]# python3 test.py
b'client.py remote_command.py server.py test.py\n' ##输出的结果是bytes类型要转换
[root@node2 socket]# cat test.py
#!/usr/local/python3/bin/python3
import subprocess
a=subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE)
print(str(a.stdout.read(),'utf8')) ##转换字符串
[root@node2 socket]# python3 test.py
client.py remote_command.py server.py test.py
3.远程命令操作实现
[root@node2 socket]# cat remote_command.py
#!/usr/local/python3/bin/python3
import socket
import subprocess ###
# family type
sk = socket.socket()
address=('127.0.0.1',8888)
sk.bind(address)
sk.listen(3)
while True:
conn, addr = sk.accept()
while True:
try:
data=conn.recv(1024)
except Exception:
break
print(str(data,'utf-8'))
if not data:break
obj=subprocess.Popen(str(data,'utf8'),shell=True,stdout=subprocess.PIPE)
##Popen是一个类,后面的是实例化的参数,实例出来的一个对象,而且data接收的是bytes类型要转换
# obj.stdout.read() #得到执行obj的结果
cmd_result=obj.stdout.read()
conn.send(cmd_result)
sk.close()
4.测试:存在问题,当重复操作时会发现命令结果不对
[root@node2 socket]# python3 remote_command.py
dir
[root@node2 socket]# python3 client.py
>>> dir
client.py remote_command.py server.py test.py
5.接收传送的大小优化
描述:运行命令的结果有限制,如果超过1024后有问题
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
[root@node2 socket]# cat client.py
#!/usr/local/python3/bin/python3
import socket
sk=socket.socket()
address=('127.0.0.1',8888)
sk.connect(address)
while True:
inp=input('>>> ')
if inp == 'exit':
break
sk.send(bytes(inp,'utf8'))
data=sk.recv(4096) #把接收的值调大,但是接收是有范围的限制的,如果更大超过了还会有问题
print(str(data,'utf-8'))
sk.close()
6.issue: 服务器可以把数据发送完,只是client数据没有真正把它接收完
解决的方法: 初始化一个变量,收到的数据加入到变量中,先使用length取得该数据的大小,与之做对比
细化: 客户端设置一次只接收1024个,但是并不知道需要接收多少次,取决于com_result发送的到底有多长,如果是1025发送两次就可以了,如果是2049就要发3次,服务端先通知client这个com_result的大小,再进行判断,如有1048个字节,最大1024,需要接收两次1024+24,再初始一个变量,类似于求和sum=0,开始接收,再把数据添加给变量,接收一次做一次判断这个文件是否等于1048的长度,再接收剩下的24个字节,回到while中判断
[root@node2 socket]# cat remote_command.py
#!/usr/local/python3/bin/python3
import socket
import subprocess
# family type
sk = socket.socket()
address=('127.0.0.1',8888)
sk.bind(address)
sk.listen(3)
while True:
conn, addr = sk.accept()
while True:
try:
data=conn.recv(1024)
except Exception:
break
print(str(data,'utf-8'))
if not data:break
obj=subprocess.Popen(data,shell=True,stdout=subprocess.PIPE)
cmd_result=obj.stdout.read()
result_len=bytes(str(len(cmd_result)),'utf8')
#len(cmd_result)是int类型,再转换成str,再到bytes,注意:str可以与int互转,bytes与str互转,int不能直接转换成bytes
conn.sendall(result_len)
conn.sendall(cmd_result)
sk.close()
[root@node2 socket]# cat client.py
#!/usr/local/python3/bin/python3
import socket
sk=socket.socket()
address=('127.0.0.1',8888)
sk.connect(address)
while True:
inp=input('>>> ')
if inp == 'exit':
break
sk.send(bytes(inp,'utf8'))
result_len=str(sk.recv(1024)) #linux中不用int强转
#result_len=int(str(sk.recv(1024))) #传输的是一个数字int,过来的是bytes类型,数字怎么也不会超过1024个字节
print(result_len)
data=bytes() #过来内容做一个初始化,bytes()是一个空的bytes
while len(data)!=result_len: #只要result_len不等于这个长度,就一直接收
recv=sk.recv(1024)
data+=recv #对接收的累加,加一次后在while中判断是不是等于原来的文件大小,不等于继续接收
print(str(data,'utf-8')) #data是bytes类型,需要转换
sk.close()
7.粘包现象以及解决办法
粘包现象错误
[root@node2 socket]# python3 client.py
>>> ifconfig
Traceback (most recent call last):
File "client.py", line 12, in <module>
result_len=int(str(sk.recv(1024),'utf8'))
ValueError: invalid literal for int() with base 10: '900eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500\n
问题: 当进行连续的两次很快的send时,它不会发送完第一次,再发第二次,而且连着第二次的一起发,第一次是数字,client端中使用int,是正常的,但是第二次时,是一堆字符串,使用int会报错,result_len=int(str(sk.recv(1024)))在int转换时,会造成有错误
分析: 在server中的conn.sendall的两行代码,首先第一行是发送一行数字(result_len),数字无论多大,占用的空间都很小,如5000多,可能占一个字节就可以,当conn.sendall(result_len)时,并不会直接发送过去,在很短的时间内会等待一下,看看后面是否还有连续发送的,但是在conn.sendall(cmd_result)中,又发送一堆的字符串,相当于一艘小船开始时,装了一点小内容,它不会开,它会等待一小段时间,然后再装了一堆的东西,一起发送过去了,这个现象是偶尔出现
conn.sendall(result_len)
conn.sendall(cmd_result)
**解决方法1:**在两个之间小停一下,但是在这始终造成一小段时间的阻塞
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
[root@node2 socket]# cat remote_command.py
#!/usr/local/python3/bin/python3
import socket
import subprocess
import time #########
# family type
sk = socket.socket()
address=('127.0.0.1',8888)
sk.bind(address)
sk.listen(3)
while True:
conn, addr = sk.accept()
while True:
try:
data=conn.recv(1024)
except Exception:
break
print(str(data,'utf-8'))
if not data:break
obj=subprocess.Popen(data,shell=True,stdout=subprocess.PIPE)
cmd_result=obj.stdout.read()
result_len=bytes(str(len(cmd_result)),'utf8')
conn.sendall(result_len) #当发送数字时,会停留一小点时间,会问下是否还有数据要发送,没有就发送了
time.sleep(1) #当加下time.sleep时会超过它等待的时间,这样时间就会变得正常
conn.sendall(cmd_result)
sk.close()
**解决方法2:**在两次发送之间,加入一个recv,把它们隔断开
[root@node2 socket]# cat remote_command.py
#!/usr/local/python3/bin/python3
import socket
import subprocess
# family type
sk = socket.socket()
address=('127.0.0.1',8888)
sk.bind(address)
sk.listen(3)
while True:
conn, addr = sk.accept()
while True:
try:
data=conn.recv(1024)
except Exception:
break
print(str(data,'utf-8'))
if not data:break
obj=subprocess.Popen(data,shell=True,stdout=subprocess.PIPE)
cmd_result=obj.stdout.read()
result_len=bytes(str(len(cmd_result)),'utf8')
conn.sendall(result_len)
conn.recv(1024) #####中间把它隔开,因为recv会阻塞不有问题,只有同时两个send时造成的
conn.sendall(cmd_result)
sk.close()
[root@node2 socket]# cat client.py
#!/usr/local/python3/bin/python3
import socket
sk=socket.socket()
address=('127.0.0.1',8888)
sk.connect(address)
while True:
inp=input('>>> ')
if inp == 'exit':
break
sk.send(bytes(inp,'utf8'))
#result_len=str(sk.recv(1024),'utf8')
result_len=int(str(sk.recv(1024),'utf8'))
sk.sendall('ok') ###server加了一个recv,client对应加上一个发送
print(result_len)
data=bytes()
while len(data)!=result_len:
recv= sk.recv(1024)
data+=recv
print(str(data,'utf-8'))
sk.close()