from socket import *
import subprocess
import struct
import json
server=socket(AF_INET,SOCK_STREAM) #创建一个服务器的套接字
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #解决方案
# 重启服务端时可能会遇到地址占用
# 这个是由于你的服务端仍然存在四次挥手的time_wait状态在占用地址
server.bind(('127.0.0.1',8080)) #把地址绑定到套接字
server.listen(5) #监听链接
while True: #链接循环,这个链接结束,继续处理下一个客户端链接,不会因为一个客户端链接结束,导致服务器结束
conn,client_addr=server.accept()
print('新的客户端',client_addr)
while True: #收发循环,实现循环通讯
try: #windows突然断开,服务端会因为没有链接 而崩溃
cmd=conn.recv(1024) #cmd=b'dir' 接收的是bytes类型 使用时要解码
if len(cmd) == 0:break #linux如果突然断开,自己给自己收空,就死循环
# 运行系统命令
obj=subprocess.Popen(cmd.decode('utf-8'), #接收的是bytes类型 使用时要解码
shell=True,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE
)
stdout=obj.stdout.read() #从管道接收正确输出,bytes类型
stderr=obj.stderr.read() #从管道接收错误输出,bytes类型
#先制作报头是字典但因为通讯是bytes类型所以要转换 dic--str--bytes
header_dic={
'filename':'a.txt',
'total_size':len(stdout) + len(stderr),
'hash':'xasf123213123'
}
header_json=json.dumps(header_dic) #先用json序列化,变成str类型
header_bytes=header_json.encode('utf-8') #str编码成bytes类型
#1、先把报头的长度len(header_bytes)打包成4个bytes,然后发送
conn.send(struct.pack('i',len(header_bytes))) #int -->bytes
#2、发送报头
conn.send(header_bytes) #报头传过去
#3、再发送真实的数据
conn.send(stdout)
conn.send(stderr)
except ConnectionResetError:
break
conn.close()
server.close()