内网通信脚本
先在服务端.py中定义IP限制和运行端口,然后运行
然后在另一台机器的客户端.py中定义服务端IP和端口,然后运行,第一条命令是“credit”,可在服务端.py自定义
服务端.py
import socketserver
import subprocess
import struct
import os
import json
import tkinter as tk
from tkinter import filedialog
def get_path(f: str, title: str, filetypes=[("all files", "*")]):
# 弹出文件选择对话框
tk.Tk().withdraw()
return getattr(filedialog, f)(title=title, filetypes=filetypes)
def get_relative_path(home_path, relative_path):
# 根据相对路径得到绝对路径
if not relative_path:
return get_path('askopenfilename', title='请选择目标文件')
if os.path.basename(relative_path) == relative_path:
return os.path.join(home_path, relative_path)
elif not relative_path.startswith('.'):
return relative_path
tmp_list = relative_path.split('/')
for tmp in tmp_list:
if tmp == '..':
home_path = os.path.dirname(home_path)
elif tmp == '.':
continue
else:
home_path = os.path.join(home_path, tmp)
return os.path.normpath(home_path)
def send_header_g(header, connect_obj):
header_bytes = json.dumps(header).encode('utf-8')
header_lenth = struct.pack('i', len(header_bytes))
connect_obj.send(header_lenth)
connect_obj.send(header_bytes)
def get_header_g(connect_obj):
header_lenth = connect_obj.recv(4)
header_szie = struct.unpack('i', header_lenth)[0]
header_bytes = connect_obj.recv(header_szie)
return json.loads(header_bytes.decode('utf-8'))
def failed_handle_r(info, connect_obj):
send_header_g(info, connect_obj)
print(info)
def failed_handle_s(info, connect_obj):
send_header_g(info, connect_obj)
print(get_header_g(connect_obj))
def send_file(cmd, connect_obj):
try:
print(cmd)
file_name = cmd[13:].strip()
print(file_name)
file_dir = get_relative_path(os.path.dirname(__file__), file_name)
file_name = os.path.basename(file_name)
except Exception:
return failed_handle_s('Cancel:2', connect_obj)
if os.path.isfile(file_dir):
total_size = os.path.getsize(file_dir)
md5_value = ''
header = {
'action': 'save_file',
'filename': file_name,
'total_szie': total_size,
'md5': md5_value
}
send_header_g(header, connect_obj)
with open(file_dir, 'rb') as f:
for line in f:
connect_obj.send(line)
result = connect_obj.recv(1024).decode('utf-8')
print(result)
else:
result = f'{file_dir} not found...'
print(result)
return failed_handle_s(f'Cancel:1', connect_obj)
def recv_file(cmd, connect_obj):
header = get_header_g(connect_obj)
print(header)
if isinstance(header, dict):
recv_size = 0
file_name = cmd.replace('upload_file', '').split('to')[-1].strip()
file_dir = get_relative_path(os.path.dirname(__file__), file_name)
if not os.path.isdir(os.path.dirname(file_dir)):
os.makedirs(os.path.dirname(file_dir))
with open(file_dir, 'wb') as f:
while recv_size < header['total_szie']:
flow = connect_obj.recv(1024)
f.write(flow)
recv_size += len(flow)
# connect_obj.send(b'done')
result = f'{file_dir} saved'
print(result)
connect_obj.send(bytes(result.encode('utf-8')))
else:
result = header
failed_handle_r(result, connect_obj)
class MyRequestHandle(socketserver.BaseRequestHandler):
def handle(self):
print(self.client_address)
self.authenticated = False
cmd = self.request.recv(24).decode('utf-8')
if cmd == 'credit': # 在此处自定义通行凭证
self.authenticated = True
self.request.send(struct.pack('i', len(b'waiting for order...')))
self.request.send(b'waiting for order...')
else:
self.request.send(struct.pack('i', len(b'password required...')))
self.request.send(b'password required & connection closing...')
while self.authenticated:
try:
cmd = self.request.recv(1024).decode('utf-8')
if len(cmd) == 0 or cmd == 'exit':
print(f'{self.client_address} 已断开连接')
break
elif cmd.startswith('download_file'):
send_file(cmd, self.request)
elif cmd.startswith('upload_file'):
recv_file(cmd, self.request)
else:
obj = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout_res = obj.stdout.read()
stderr_res = obj.stderr.read()
res = stdout_res + stderr_res
res_size = struct.pack('i', len(res))
self.request.send(res_size)
self.request.send(res)
except ConnectionResetError:
break
self.request.close()
s = socketserver.ThreadingTCPServer(('0.0.0.0', 9527), MyRequestHandle) # 在此处自定义IP和PORT
s.serve_forever()
客户端.py
import os
import json
import struct
import re
import tkinter as tk
from tkinter import filedialog
from socket import *
def get_path(f: str, title: str, filetypes=[("all files", "*")]):
# 弹出文件选择对话框
# tk.Tk().withdraw()
return getattr(filedialog, f)(title=title, filetypes=filetypes)
def get_relative_path(home_path, relative_path):
# 根据相对路径得到绝对路径
relative_path = relative_path.strip()
if not relative_path:
return get_path('askopenfilename', title='请选择目标文件')
if os.path.basename(relative_path) == relative_path:
return os.path.join(home_path, relative_path)
elif not relative_path.startswith('.'):
return relative_path
tmp_list = relative_path.split('/')
for tmp in tmp_list:
if tmp == '..':
home_path = os.path.dirname(home_path)
elif tmp == '.':
continue
else:
home_path = os.path.join(home_path, tmp)
return os.path.normpath(home_path)
def send_header_g(header, connect_obj):
header_bytes = json.dumps(header).encode('utf-8')
header_lenth = struct.pack('i', len(header_bytes))
connect_obj.send(header_lenth)
connect_obj.send(header_bytes)
def get_header_g(connect_obj):
header_lenth = connect_obj.recv(4)
header_szie = struct.unpack('i', header_lenth)[0]
header_bytes = connect_obj.recv(header_szie)
return json.loads(header_bytes.decode('utf-8'))
def failed_handle_r(info, connect_obj):
send_header_g(info, connect_obj)
print(info)
def failed_handle_s(info, connect_obj):
send_header_g(info, connect_obj)
print(get_header_g(connect_obj))
def send_file(cmd, connect_obj):
try:
file_name = cmd.replace('upload_file', '').split('to')[0].strip()
server_test = cmd.replace('upload_file', '').split('to')[-1].strip()
# file_dir命名失误,应为目标文件的绝对路径
file_dir = get_relative_path(os.path.dirname(__file__), file_name)
file_name = os.path.basename(file_name)
print(f'file_dir: {file_dir}')
except Exception:
return failed_handle_s('Cancel:2', connect_obj)
if os.path.isfile(file_dir) and (server_test.isalpha() or re.match('\S.\S', server_test)):
total_size = os.path.getsize(file_dir)
md5_value = ''
header = {
'action': 'save_file',
'filename': file_name,
'total_szie': total_size,
'md5': md5_value
}
send_header_g(header, connect_obj)
with open(file_dir, 'rb') as f:
for line in f:
connect_obj.send(line)
result = connect_obj.recv(1024).decode('utf-8')
print(result)
else:
return failed_handle_s('Cancel:1', connect_obj)
# 1: file not found or server target error
# 2: The command could not be resolved
def recv_file(connect_obj):
header = get_header_g(connect_obj)
print(header)
if isinstance(header, dict):
recv_size = 0
try:
ftps = os.path.splitext(header['filename'])[-1]
up_ftps = ftps.replace('.', '').upper()
print(f'ftps: {ftps}, up_ftps: {up_ftps}')
file_dir = get_path('asksaveasfilename', title='请选择保存文件路径', filetypes=[(up_ftps, ftps)])
print(file_dir)
except Exception:
file_dir = get_path('asksaveasfilename', title='请选择保存文件路径', )
# if not os.path.isdir(os.path.dirname(file_dir)):
# os.makedirs(os.path.dirname(file_dir))
with open(file_dir, 'wb') as f:
while recv_size < header['total_szie']:
flow = connect_obj.recv(1024)
f.write(flow)
recv_size += len(flow)
result = f'{file_dir} saved'
print(result)
connect_obj.send(bytes(result.encode('utf-8')))
else:
result = header
failed_handle_r(result, connect_obj)
client = socket(AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1', 9527))
while True:
msg = input('请输入要发送的命令:').strip()
if len(msg) == 0: continue
client.send(msg.encode('utf-8'))
if msg == 'exit':
client.close()
break
elif msg.startswith('download_file '): # download_file server_file_path
recv_file(client)
elif msg.startswith('upload_file '): # upload_file file_path to server_file_path
send_file(msg, client)
else:
cmd_res_size = struct.unpack('i', client.recv(4))[0]
cmd_res = b''
while len(cmd_res) < cmd_res_size:
cmd_res += client.recv(1024)
print(cmd_res.decode('utf-8'))
if cmd_res.decode('utf-8') == 'password required & connection closing...':
client.close()
break