内网通信脚本

Posted on 2022-11-27 21:19  呱呱呱呱叽里呱啦  阅读(60)  评论(0编辑  收藏  举报

内网通信脚本

先在服务端.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