网络通信之:服务端远程执行客户端命令
服务端:
import socket,subprocess sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM) sk.bind(('localhost',8080)) sk.listen(5) while True: conn,client_addr = sk.accept() print(conn) print('客户端的ip和端口:',client_addr) while True: try: data = conn.recv(8096) print('客户端ip:%s,消息:%s '%(client_addr[0],data.decode('utf-8'))) if len(data) == 0:break res = subprocess.Popen(data.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) msg = res.stdout.read() if len(msg)==0: msg= res.stderr.read() conn.send(msg) except Exception: break conn.close() sk.close()
客户端:
import socket sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM) sk.connect(('127.0.0.1',8080)) while True: msg = input('>>>>>>>:').strip() if len(msg) == 0:continue sk.send(msg.encode('utf-8')) data = sk.recv(8096) print('服务端发来消息:',data.decode('gbk')) sk.close()
以上代码可以实现务端远程执行客户端命令,但是会出现粘包问题,下面来解决粘包问题:
方案一
服务端:
import struct import socket,subprocess server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) server.bind(('127.0.0.1',8080)) server.listen(5) while True: conn,client_addr = server.accept() print(conn) print('客户端的ip和端口是:',client_addr) while True: try: data = conn.recv(1024) if len(data)==0:break print('客户端的ip是:%s,客户端的消息是:%s' %(client_addr[0],data.decode('utf-8'))) res = subprocess.Popen(data.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) stdout_res = res.stdout.read() stderr_res = res.stdout.read() total_size = len(stdout_res)+len(stderr_res) print(total_size) # 1.先发头信息(固定长度的Bytes):对数据的描述 # int->固定长度的Bytes # conn.send(str(total_size).encode('utf-8')) #原来的方案 header = struct.pack('i',total_size) conn.send(header) # 2.再发真实数据 conn.send(stdout_res) conn.send(stderr_res) except Exception: break conn.close() server.close()
客户端:
import socket import struct client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) client.connect(('127.0.0.1',8080)) while True: msg = input('>>>>>>>:').strip() if len(msg) == 0:continue client.send(msg.encode('utf-8')) # 解决粘包问题思路: # 一.先收固定长度的头:解析出数据的描述信息,包括数据的总大小total_size header = client.recv(4) total_size = struct.unpack('i',header)[0] # 二、根据解析出的描述信息,接收真实的数据 # 2.recv_size=0,循环接收,每接受一次,recv_size += 接收的长度 # 3.直到recv_size = total_size,结束循环 recv_size = 0 while recv_size < total_size: recv_data = client.recv(1024) recv_size += len(recv_data) print(recv_data.decode('gbk'),end='') else: print() # data = client.recv(8096) # print('服务端发来的消息:',data.decode('gbk')) client.close()
终极版-解决粘包问题
服务端:
import socket import subprocess import struct import json server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) server.bind(('127.0.0.1',8080)) server.listen(5) while True: conn,client_addr = server.accept() print(conn) print('客户端的ip和端口是:',client_addr) while True: try: data = conn.recv(1024) if len(data) ==0: break print('客户端的ip是:%s,客户端发来的消息是:%s' %(client_addr[0],data.decode('utf-8'))) res = subprocess.Popen(data.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) stdout_res = res.stdout.read() stderr_res = res.stderr.read() total_size = len(stdout_res) + len(stderr_res) print('服务端执行后的消息长度为:',total_size) # 一、制作头 header_dic = { 'filename':'a.txt', 'total_size':total_size, 'md5':'fadfadsfdf' } json_str = json.dumps(header_dic) json_str_bytes = json_str.encode('utf-8') # 1.先把头的长度发过去 x = struct.pack('i',len(json_str_bytes)) conn.send(x) # 2.发头信息 conn.send(json_str_bytes) # 2.再发真实信息 conn.send(stdout_res) conn.send(stderr_res) except Exception: break conn.close() server.close()
客户端:
import socket
import struct
import json
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('127.0.0.1',8080))
while True:
msg = input('>>>>>>>:').strip()
if len(msg) == 0:continue
client.send(msg.encode('utf-8'))
# 接收端
# 1.先接收4个字节,从中提取出头部长度
x = client.recv(4)
header_len = struct.unpack('i',x)[0]
# 2.接收头,并解析
json_str_bytes = client.recv(header_len)
json_str = json_str_bytes.decode('utf-8')
header_dic = json.loads(json_str)
print(header_dic)
total_size = header_dic['total_size']
recv_size = 0
while recv_size < total_size:
recv_data = client.recv(1024)
recv_size += len(recv_data)
print(recv_data.decode('gbk'),end='')
else:
print()
client.close()