9.user input and frame listener

本文深入探讨了游戏引擎在三维渲染技术中的应用,详细介绍了Ogre引擎的基本框架、帧监听器的实现以及如何通过输入系统(OIS)和帧监听器处理用户的键盘和鼠标输入。同时,文章还涉及了如何利用定时器来控制特定操作的执行间隔,以及如何通过改变多边形模式来动态调整场景的视觉效果。

这一次整整把一章看完了,那就一下子来一章的内容吧。

用户输入主要包括键盘和鼠标输入,要处理这两类信息,必须使用OIS和frame listener。这需要创建一个新类继承Ogre中基本的framelistener,然后在构造函数中创建OIS系统和需要监控的设备,对信息的处理可以在framestarted中进行,也可以在frameended或者framerenderingqueue中进行,对输入的处理貌似一般在started中进行。

这次还用到了一个定时器timer,用来确定两次按键间隔大于0.25s,好用易懂,reset就好了。

要注意OIS系统的初始化、使用和析构。

#include "Ogre\ExampleApplication.h"

class Example25FrameListener:public Ogre::FrameListener
{
public:
	Example25FrameListener(RenderWindow* win, Ogre::Camera* cam)
	{
		this ->_movementspeed = 3;

		size_t windowHnd = 0;                                   //从这里开始OIS系统的初始化,主要提供窗口句柄windowHnd
		std::stringstream windowHndStr;
		win ->getCustomAttribute("WINDOW", &windowHnd);
		windowHndStr << windowHnd;
		OIS::ParamList pl;
		pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));

		_man = OIS::InputManager::createInputSystem(pl);       //创建系统和设备
		_key = static_cast<OIS::Keyboard*>(_man ->createInputObject(OIS::OISKeyboard, false));
		_mouse = static_cast<OIS::Mouse*>(_man ->createInputObject(OIS::OISMouse, false));

		_Cam = cam;

		_PolyMode = Ogre::PolygonMode::PM_SOLID;

		_timer.reset();
	}

	~Example25FrameListener()
	{
		_man ->destroyInputObject(_key);
		_man ->destroyInputObject(_mouse);
		OIS::InputManager::destroyInputSystem(_man);
	}

	bool frameStarted(const Ogre::FrameEvent& evt)
	{
		Ogre::Vector3 translate(0, 0, 0);
		_key ->capture();
		_mouse ->capture();

		if(_key ->isKeyDown(OIS::KC_R) && _timer.getMilliseconds() > 250)//多边形模式的变化,这里用到了timer
		{
			if(_PolyMode == Ogre::PolygonMode::PM_SOLID)
			{
				_PolyMode = Ogre::PolygonMode::PM_WIREFRAME;
			}
			else if(_PolyMode == Ogre::PolygonMode::PM_WIREFRAME)
			{
				_PolyMode = Ogre::PolygonMode::PM_POINTS;
			}
			else if(_PolyMode == Ogre::PolygonMode::PM_POINTS)
			{
				_PolyMode = Ogre::PolygonMode::PM_SOLID;
			}
			_Cam ->setPolygonMode(_PolyMode);
			_timer.reset();
		}

		if(_key ->isKeyDown(OIS::KC_W))                //镜头的位移
		{
			translate += Ogre::Vector3(0, 0, -10);
		}
		if(_key ->isKeyDown(OIS::KC_S))
		{
			translate += Ogre::Vector3(0, 0, 10);
		}
		if(_key ->isKeyDown(OIS::KC_A))
		{
			translate += Ogre::Vector3(-10, 0, 0);
		}
		if(_key ->isKeyDown(OIS::KC_D))
		{
			translate += Ogre::Vector3(10, 0, 0);
		}
		
		float rotX = _mouse ->getMouseState().X.rel * evt.timeSinceLastFrame * (-0.5);  //镜头的旋转
		float rotY = _mouse ->getMouseState().Y.rel * evt.timeSinceLastFrame * (-0.5);

		_Cam ->yaw(Ogre::Radian(rotX));
		_Cam ->pitch(Ogre::Radian(rotY));
		_Cam ->moveRelative(translate * evt.timeSinceLastFrame * _movementspeed);

		if(_key ->isKeyDown(OIS::KC_ESCAPE))
		{
			return false;
		}

		return true;
	}

private:
	OIS::InputManager* _man;
	OIS::Keyboard* _key;
	Ogre::Camera* _Cam;
	OIS::Mouse* _mouse;
	size_t _movementspeed;
	Ogre::PolygonMode _PolyMode;
	Ogre::Timer _timer;
};

class Example25:public ExampleApplication
{
public:
	Ogre::FrameListener* FrameListener;

	Example25()
	{
		FrameListener = NULL;
	}

	~Example25()
	{
		if(FrameListener)
		{
			delete FrameListener;
		}
	}

	void createFrameListener()
	{
		FrameListener = new Example25FrameListener(mWindow, mCamera);
		mRoot ->addFrameListener(FrameListener);
	}

	void createScene()
	{
		Ogre::Plane plane(Vector3::UNIT_Y, -10);
		Ogre::MeshManager::getSingleton().createPlane("plane", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
			plane, 1500, 1500, 200, 200, true, 1, 5, 5, Vector3::UNIT_Z);
		Ogre::Entity* ent = mSceneMgr ->createEntity("LightPlaneEntity", "plane");
		mSceneMgr ->getRootSceneNode() ->createChildSceneNode() ->attachObject(ent);
		ent ->setMaterialName("Examples/BeachStones");

		Ogre::Light* light = mSceneMgr ->createLight("Light1");
		light ->setType(Ogre::Light::LT_DIRECTIONAL);
		light ->setDirection(Ogre::Vector3(1, -1, 0));

		Ogre::SceneNode* node = mSceneMgr ->createSceneNode("Node1");
		mSceneMgr ->getRootSceneNode() ->addChild(node);

		Ogre::Entity* Sinbad = mSceneMgr ->createEntity("Sinbad", "Sinbad.mesh");
		_SinbadNode = node ->createChildSceneNode("SinbadNode");
		_SinbadNode ->setScale(3.0f, 3.0f, 3.0f);
		_SinbadNode ->setPosition(Ogre::Vector3(0.0f, 4.0f, 0.0f));
		_SinbadNode ->attachObject(Sinbad);

		mSceneMgr ->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE);
	}
	
	void createCamera()
	{
		mCamera = mSceneMgr ->createCamera("MyCamera1");
		mCamera ->setPosition(0, 100, 200);
		mCamera ->lookAt(0, 0, 0);
		mCamera ->setNearClipDistance(5);
	}
	
private:
	Ogre::SceneNode* _SinbadNode;
};

int main(void)
{
	Example25 app;
	app.go();
	return 0;
}


09-23 11:33:20.279 6102 26201 26201 I XBaseDownloadActivity: showInstallFailedDialog OK 09-23 11:33:20.279 6102 26201 26201 I XBaseDownloadActivity: showDialogNoFullDown 09-23 11:33:20.283 1002 7313 7549 I BtGatt.ScanManager: msg.what = MSG_SCREEN_ON, msg.arg1 = None 09-23 11:33:20.283 10158 3667 3667 W Launcher: onDisplayChanged: newRotation=0, mCurrentRotation=0 09-23 11:33:20.283 6102 26201 26201 D AlertController: Alert dialog ime debugEnable = 09-23 11:33:20.283 1000 1573 1573 E HwcComposer: presentOrValidateDisplay 0 presentFence:-1 09-23 11:33:20.284 10158 3667 3829 W GestureStubView_Left: onDisplayChanged 09-23 11:33:20.285 10158 3667 3829 W GestureStubView_Left: adaptRotation currentRotation=0 mRotation=0 09-23 11:33:20.286 radio 3629 28975 D HighSpeedTrainModeController: msg.what = 7 09-23 11:33:20.286 10158 3667 3829 W GestureStubView_Right: onDisplayChanged 09-23 11:33:20.286 10158 3667 3829 W GestureStubView_Right: adaptRotation currentRotation=0 mRotation=0 09-23 11:33:20.287 radio 3629 28634 D NetworkSpeedTracker: onDisplayChanged mIsScreenOn=true 09-23 11:33:20.287 radio 3629 28634 D NetworkSpeedTracker: onUpdateDeviceState eventType=4,mIsScreenOn=true,mIsMobileDataOn=false 09-23 11:33:20.287 radio 3629 28634 D NetworkSpeedTracker: stopDataPoll 09-23 11:33:20.288 radio 3629 3629 D FivegOfflineStatistic: onDisplayChanged, mIsScreenOn = true, mScreenOnStartTime = 312490879, mScreenOnTotalTime = 6366524 09-23 11:33:20.290 6102 26201 26201 D ScrollerOptimizationManager: registerConfigChangedListener 09-23 11:33:20.291 1000 1573 1573 E HwcComposer: presentOrValidateDisplay 0 presentFence:-1 09-23 11:33:20.296 1000 2505 4588 D CameraCoveredManager: cloud ScreenAntiBurnData is null 09-23 11:33:20.298 6102 26201 26201 I ViewRootImpl: com.android.updater/com.android.updater.UpdateActivity use first frame acceleration 09-23 11:33:20.300 1000 2505 4588 I whetstone.activity: Power Event callback listener is empty for resId=32 09-23 11:33:20.300 1000 2505 4588 D BatteryStatsManagerStub: notifyEvent for resId=32 used 0ms 09-23 11:33:20.301 1000 2505 4588 D WindowManager: wms.Input focus has changed to Window{a2ed6f5 u0 com.android.updater/com.android.updater.UpdateActivity} display=0 updateInputWindows = false 09-23 11:33:20.301 1000 2505 4588 I MultiSenceManagerInternalStub: getInstance 09-23 11:33:20.301 1000 2505 3269 I MultiSenceManagerInternalStubImpl: packageName = com.android.updater 09-23 11:33:20.302 1000 2505 3269 W ContextImpl: Calling a method in the system process without a qualified user: android.app.ContextImpl.sendBroadcast:1260 com.android.server.wm.MultiSenceManagerInternalStubImpl.sendFocusWindowsBroadcast:153 com.android.server.wm.MultiSenceManagerInternalStubImpl$UpdateScreenStatus.run:98 android.os.Handler.handleCallback:959 android.os.Handler.dispatchMessage:100 09-23 11:33:20.302 1000 2505 2595 D WindowManager: wms.Focus not requested for window=Window{a2ed6f5 u0 com.android.updater/com.android.updater.UpdateActivity} because it has no surface or is not focusable. 09-23 11:33:20.302 1000 2505 3269 W ActivityManagerServiceImpl: Sending non-protected broadcast com.xiaomi.multisence.action.FOCUSED_CHANGE from system 2505:system/1000 pkg android 09-23 11:33:20.302 6102 26201 26201 I Choreographer: first vsync insert message into MessageQueue Head 09-23 11:33:20.303 6102 26201 26201 D DecorViewImmersiveImpl: onAttachedToWindow:com.android.updater/com.android.updater.UpdateActivity 09-23 11:33:20.304 1000 2505 4588 D CoreBackPreview: Window{a2ed6f5 u0 com.android.updater/com.android.updater.UpdateActivity}: Setting back callback OnBackInvokedCallbackInfo{mCallback=android.window.IOnBackInvokedCallback$Stub$Proxy@90204c4, mPriority=0, mIsAnimationCallback=false} 09-23 11:33:20.307 1000 2505 4588 D MiuiRefreshRatePolicy: reset
09-24
1.”# E:\AI_System\main.py (完全E盘操作版) import os import sys import traceback import time import logging import signal import json from pathlib import Path from core.config import config from core.command_listener import start_command_listener from agent.model_manager import ModelManager from agent.cognitive_architecture import CognitiveSystem from utils.path_utils import normalize_path, clean_path_cache ====================== 基础路径配置 ====================== 确保所有操作都在E盘 BASE_DRIVE = “E:” # 固定使用E盘 PROJECT_ROOT = Path(file).parent.resolve() # 项目根目录在E盘 WORKSPACE_PATH = Path(BASE_DRIVE) / “AI_Workspace” # 工作空间根路径 必要目录 WORKSPACE_PATH.mkdir(parents=True, exist_ok=True) ====================== 日志配置 ====================== def setup_logging() -> logging.Logger: “”“配置日志系统(完全在E盘操作)”“” # 日志目录(必须在E盘) logs_dir = WORKSPACE_PATH / “logs” try: # 日志目录 logs_dir.mkdir(parents=True, exist_ok=True) # 配置日志级别 log_level_name = config.get("log_level", "INFO").upper() log_level_mapping = { "DEBUG": logging.DEBUG, "INFO": logging.INFO, "WARNING": logging.WARNING, "ERROR": logging.ERROR, "CRITICAL": logging.CRITICAL } log_level = log_level_mapping.get(log_level_name, logging.INFO) # 配置日志格式 log_format = "%(asctime)s - [%(levelname)s] - %(name)s - %(message)s" formatter = logging.Formatter(log_format) # 配置根日志记录器 root_logger = logging.getLogger() root_logger.setLevel(log_level) # 移除所有现有处理器 for handler in root_logger.handlers[:]: root_logger.removeHandler(handler) # 日志文件(在E盘) log_file = logs_dir / f"system_{time.strftime(&#39;%Y%m%d_%H%M%S&#39;)}.log" try: file_handler = logging.FileHandler(log_file, encoding=&#39;utf-8&#39;) file_handler.setFormatter(formatter) root_logger.addHandler(file_handler) except Exception as e: # 日志文件失败时使用控制台 print(f"⚠️ 无法日志文件: {e}") # 添加控制台处理器 console_handler = logging.StreamHandler() console_handler.setFormatter(formatter) root_logger.addHandler(console_handler) # 主日志记录器 main_logger = root_logger.getChild("Main") main_logger.info(f"日志系统初始化完成 (级别: {log_level_name})") main_logger.info(f"日志文件位置: {log_file}") return main_logger except Exception as e: # 完全失败时的后备方案 print(f"🔥 日志配置失败: {e}") return logging.getLogger("FallbackLogger") ====================== 模型路径处理 ====================== def get_model_paths(model_name: str) -> list: “”“返回所有可能的模型路径(仅限E盘)”“” return [ WORKSPACE_PATH / “AI_Models” / model_name, # 首选位置 Path(BASE_DRIVE) / “AI_Models” / model_name, # 备选位置1 Path(BASE_DRIVE) / “Models” / model_name, # 备选位置2 WORKSPACE_PATH / “models” / model_name # 项目内置模型 ] def find_valid_model_path(model_name: str, logger: logging.Logger) -> Path: “”“在E盘查找有效的模型路径”“” possible_paths = get_model_paths(model_name) for path in possible_paths: if path.exists(): logger.info(f"✅ 找到模型路径: {path}") return path # 没有找到有效路径 logger.critical(f"🛑 在E盘找不到模型: {model_name}") logger.critical("检查位置:") for path in possible_paths: logger.critical(f" - {path}") raise FileNotFoundError(f"在E盘找不到模型: {model_name}") ====================== 主函数 ====================== def main(): “”“主函数(完全E盘操作)”“” # 清理路径缓存 clean_path_cache() # 设置日志 logger = setup_logging() # 记录启动信息 logger.info("=" * 50) logger.info(f"🌟 启动AI系统 - 弹性星型架构") logger.info(f"🚀 工作空间: {WORKSPACE_PATH}") logger.info(f"📂 项目目录: {PROJECT_ROOT}") logger.info(f"🐍 Python版本: {sys.version}") logger.info(f"🖥️ 操作系统: {sys.platform}") logger.info("=" * 50) # 初始化模型管理器 try: model_manager_config = config.get("model_manager", {}) # 模型缓存目录(在E盘) cache_dir = WORKSPACE_PATH / "model_cache" cache_dir.mkdir(parents=True, exist_ok=True) model_manager = ModelManager( config=config, cache_dir=str(cache_dir), use_gpu=model_manager_config.get("use_gpu", True), max_models_in_memory=model_manager_config.get("max_models_in_memory", 3) ) logger.info("✅ 模型管理器初始化完成") except Exception as e: logger.error(f"❌ 模型管理器初始化失败: {e}", exc_info=True) sys.exit(1) # 加载基础模型(仅在E盘查找) base_model_key = "TEXT_BASE" model_settings = config.get("model_settings", {}) base_model_info = model_settings.get(base_model_key, {}) model_type = base_model_info.get("type", "text") model_name = base_model_info.get("name", "Qwen2-7B") # 默认模型称 try: # 查找模型路径 model_path = find_valid_model_path(model_name, logger) # 注册加载模型 if model_manager.register_model(base_model_key, str(model_path), model_type): success, model = model_manager.load_model(base_model_key) if success: logger.info(f"✅ 基础模型加载成功: {base_model_key}") else: logger.error(f"❌ 模型加载失败: {base_model_key}") raise RuntimeError(f"模型加载失败: {base_model_key}") else: logger.error(f"❌ 模型注册失败: {base_model_key}") raise RuntimeError(f"模型注册失败: {base_model_key}") except Exception as e: logger.error(f"❌ 模型初始化失败: {e}", exc_info=True) sys.exit(1) # 初始化认知系统 try: cognitive_config = config.get("cognitive_config", {}) # 认知系统状态存储(在E盘) state_dir = WORKSPACE_PATH / "system_state" state_dir.mkdir(parents=True, exist_ok=True) cognitive_config["state_dir"] = str(state_dir) cognitive_system = CognitiveSystem( name="认知系统", model_manager=model_manager, config=cognitive_config ) # 初始化认知系统 if cognitive_system.initialize(): logger.info("✅ 认知系统初始化成功") else: raise RuntimeError("认知系统初始化失败") except Exception as e: logger.error(f"❌ 认知系统初始化失败: {e}", exc_info=True) sys.exit(1) # 令处理器 def command_handler(command: str) -> dict: """处理用户令""" logger.info(f"🔄 处理令: {command}") # 特殊令处理 if command.lower() in ["exit", "quit", "stop"]: return {"action": "shutdown", "message": "正在关闭系统..."} if command.lower() in ["status", "health"]: return cognitive_system.get_system_status() try: # 通过认知系统处理令 return cognitive_system.process_command(command) except Exception as e: logger.error(f"❌ 令处理错误: {e}", exc_info=True) return {"error": f"处理令时出错: {e}"} # 系统关闭处理 def shutdown_handler(): """系统关闭处理""" logger.info("🛑 关闭系统中...") try: # 保存状态 if cognitive_system: logger.info("💾 保存认知系统状态...") cognitive_system.save_state() # 关闭认知系统 if cognitive_system: logger.info("🛑 关闭认知系统...") cognitive_system.shutdown() # 关闭模型管理器 if model_manager: logger.info("🛑 关闭模型管理器...") model_manager.shutdown() # 停止令监听器 if &#39;command_listener&#39; in locals() and command_listener.running: logger.info("📵 停止令监听器...") command_listener.stop() logger.info("✅ 系统已完全关闭") sys.exit(0) except Exception as e: logger.error(f"❌ 关闭过程中出错: {e}", exc_info=True) sys.exit(1) # 信号处理 def signal_handler(sig, frame): """处理系统信号""" signals = {signal.SIGINT: "Ctrl+C", signal.SIGTERM: "终止信号"} logger.warning(f"⚠️ 收到 {signals.get(sig, sig)},关闭系统...") shutdown_handler() signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) # 启动令监听器 try: command_listener = start_command_listener(command_handler=command_handler) logger.info("✅ 令监听器已启动") except Exception as e: logger.error(f"❌ 令监听器启动失败: {e}", exc_info=True) shutdown_handler() return logger.info("🌟 系统准备就绪! 输入令开始交互 (&#39;help&#39; 查看令列表)") # 主循环 try: while True: # 处理令队列 while not command_listener.command_queue.empty(): command = command_listener.command_queue.get() response = command_handler(command) # 处理关闭指令 if isinstance(response, dict) and response.get("action") == "shutdown": shutdown_handler() return # 打印响应 if response: print("\n" + ("-" * 50)) if isinstance(response, dict): response_str = json.dumps(response, indent=2, ensure_ascii=False) print(f"系统响应:\n{response_str}") else: print(f"系统响应: {str(response)}") print("-" * 50 + "\n") # 休眠避免CPU占用过高 time.sleep(0.1) except KeyboardInterrupt: logger.info("🛑 用户中断操作,关闭系统...") shutdown_handler() except Exception as e: logger.critical(f"🔥 主循环错误: {e}", exc_info=True) shutdown_handler() if name == “main”: # 全局异常处理 def global_exception_handler(exc_type, exc_value, exc_traceback): “”“全局异常处理器”“” if issubclass(exc_type, KeyboardInterrupt): sys.excepthook(exc_type, exc_value, exc_traceback) return logging.error( "未捕获的全局异常", exc_info=(exc_type, exc_value, exc_traceback) ) print(f"🔥 严重错误: {exc_type.__name__}: {exc_value}") sys.exit(1) sys.excepthook = global_exception_handler # 启动主函数 try: main() except Exception as e: print(f"🔥 主函数异常: {e}") traceback.print_exc() sys.exit(1) “ 2.”# E:\AI_System\agent\environment_interface.py import logging import time import queue import threading import json from typing import Any, Optional, Dict, List from agent.base_module import UnifiedCognitiveModule from core.message import Message, MessageType class EnvironmentInterface(UnifiedCognitiveModule): “”“环境交互接口 - 完整实现”“” def __init__( self, name: str = "EnvironmentInterface", coordinator: Optional[Any] = None, config: Optional[Dict] = None ): super().__init__(name=name, coordinator=coordinator, config=config) # 配置参数 config = config or {} self.max_workers = config.get("max_workers", 4) self.response_timeout = config.get("response_timeout", 30.0) self.log_level = config.get("log_level", "INFO") # 日志配置 self.logger = logging.getLogger(name) log_level = getattr(logging, self.log_level.upper(), logging.INFO) self.logger.setLevel(log_level) # 输入输出队列 self.input_queue = queue.Queue() self.output_queue = queue.Queue() # 线程控制 self.running = True self.message_thread = threading.Thread(target=self._process_messages, daemon=True) self.message_thread.start() def shutdown(self) -> bool: """关闭环境接口""" try: self.running = False if self.message_thread.is_alive(): self.message_thread.join(timeout=2.0) super().shutdown() self.logger.info("🛑 环境接口已关闭") return True except Exception as e: self.logger.error(f"❌ 关闭失败: {str(e)}") return False def process(self, input_data: Any) -> dict: """处理输入数据""" if isinstance(input_data, dict): self.add_input(input_data) return {"status": "queued"} elif isinstance(input_data, str): self.add_input({"command": input_data}) return {"status": "queued"} else: return {"error": "不支持的输入型"} def _process_messages(self): """处理消息的后台线程""" while self.running: try: # 获取用户输入 user_input = self.get_input(timeout=0.5) if user_input: # 发送到认知系统 message = Message( msg_type=MessageType.EVENT, sender=self.name, content=user_input, target="CognitiveSystem" ) self.send_message(message) self.logger.debug(f"📤 发送用户输入: {user_input[&#39;command&#39;][:20]}...") # 处理输出队列 if not self.output_queue.empty(): output = self.output_queue.get_nowait() self._display_output(output) except Exception as e: self.logger.error(f"消息处理出错: {str(e)}") time.sleep(0.1) def handle_message(self, message: Message): """处理接收到的消息""" if message.target and message.target != self.name: return self.logger.debug(f"📩 收到消息 [{message.sender}]: {message.msg_type.name}") # 根据消息型处理 if message.msg_type == MessageType.DATA: self.output(message.content) elif message.msg_type == MessageType.RESPONSE: self.output(message.content) elif message.msg_type == MessageType.STATUS: self.logger.info(f"系统状态更: {message.content}") def get_input(self, timeout: float = 0.5) -> Optional[Dict]: """获取输入""" try: return self.input_queue.get(timeout=timeout) except queue.Empty: return None def output(self, response: Any): """添加响应""" self.output_queue.put(response) def _display_output(self, response: Any): """格式化显示输出""" try: # 处理不同型的响应 if isinstance(response, dict): response.setdefault("timestamp", time.time()) response.setdefault("source", "system") response_str = json.dumps(response, ensure_ascii=False, indent=2) print(f"<< {response_str}") if "message" in response: self.logger.info(f"💬 系统响应: {response[&#39;message&#39;]}") else: self.logger.info("💬 系统响应: 无内容") elif isinstance(response, str): print(f"<< {response}") self.logger.info(f"💬 系统响应: {response}") elif isinstance(response, Message): print(f"<< [Message from {response.sender}]: {response.content[:50]}...") self.logger.info(f"💬 收到消息响应: {response.content[:50]}...") else: response_str = str(response) print(f"<< {response_str}") self.logger.info(f"💬 系统响应: {response_str}") except Exception as e: self.logger.error(f"输出响应失败: {str(e)}") def add_input(self, input_data: dict): """添加输入""" if not isinstance(input_data, dict): self.logger.error("输入数据格式错误,必须是字典") return input_data.setdefault("timestamp", time.time()) input_data.setdefault("source", "user") self.input_queue.put(input_data) self.logger.debug(f"手动添加输入: {input_data[&#39;command&#39;][:20]}...") def get_health_status(self) -> dict: """返回模块健康状态""" return { "status": "running" if self.running else "stopped", "module": self.name, "queue_size": self.input_queue.qsize(), "last_activity": time.time(), "output_queue_size": self.output_queue.qsize() } “ 3.”# E:\AI_System\agent\model_manager.py import os import sys import logging import json import hashlib import gc import time from pathlib import Path from typing import Dict, Any, Optional, Tuple, List from utils.path_utils import normalize_path, is_valid_hf_id class ModelManager: “”“AI模型管理器 - 完整修复版”“” MODEL_REGISTRY_FILE = "model_registry.json" DEFAULT_MODEL_PATHS = { "TEXT_BASE": "local_models/text_base", "TEXT_CHAT": "local_models/text_chat", "IMAGE_MODEL": "local_models/image_model" } def __init__(self, config: Dict[str, Any] = None, cache_dir: str = "model_cache", use_gpu: bool = True, max_models_in_memory: int = 3): # 配置日志 self.logger = logging.getLogger("ModelManager") self.logger.setLevel(logging.INFO) if not self.logger.handlers: handler = logging.StreamHandler() formatter = logging.Formatter( &#39;%(asctime)s - %(name)s - %(levelname)s - %(message)s&#39;, datefmt=&#39;%Y-%m-%d %H:%M:%S&#39; ) handler.setFormatter(formatter) self.logger.addHandler(handler) self.logger.info("🚀 初始化模型管理器...") # 初始化参数 self.config = config or {} self.cache_dir = normalize_path(cache_dir) # 使用路径规范化 self.use_gpu = use_gpu self.max_models_in_memory = max_models_in_memory # 确保缓存目录存在 os.makedirs(self.cache_dir, exist_ok=True) # 加载或注册表 self._persistent_registry = self._load_or_create_registry() # 已加载的模型 self.loaded_models: Dict[str, Any] = {} # 自动注册默认模型 self._register_default_models() self.logger.info(f"✅ 模型管理器初始化完成 (GPU: {&#39;启用&#39; if use_gpu else &#39;禁用&#39;})") self.logger.info(f"已注册模型: {list(self._persistent_registry.keys())}") def _load_or_create_registry(self) -> Dict[str, dict]: """加载或模型注册表""" try: registry_path = Path(normalize_path(self.MODEL_REGISTRY_FILE)) # 路径规范化 if registry_path.exists(): with open(registry_path, &#39;r&#39;, encoding=&#39;utf-8&#39;) as f: registry = json.load(f) self.logger.info(f"📋 成功加载模型注册表: {registry_path}") return registry self.logger.warning(f"⚠️ 模型注册表不存在,文件: {registry_path}") with open(registry_path, &#39;w&#39;, encoding=&#39;utf-8&#39;) as f: json.dump({}, f, indent=2) return {} except Exception as e: self.logger.error(f"❌ 处理模型注册表失败: {str(e)}") return {} def _register_default_models(self): """注册配置文件中的默认模型""" model_settings = self.config.get("model_settings", {}) # 合默认路径和配置路径 default_paths = {**self.DEFAULT_MODEL_PATHS, **{ name: info.get("path", self.DEFAULT_MODEL_PATHS.get(name, "")) for name, info in model_settings.items() }} # 注册模型 for model_name, model_path in default_paths.items(): if model_name not in self._persistent_registry: abs_path = normalize_path(model_path) # 路径规范化 model_type = model_settings.get(model_name, {}).get("type", "text") self.register_model(model_name, abs_path, model_type) def _save_registry(self): """保存模型注册表""" try: registry_path = normalize_path(self.MODEL_REGISTRY_FILE) # 路径规范化 with open(registry_path, &#39;w&#39;, encoding=&#39;utf-8&#39;) as f: json.dump(self._persistent_registry, f, indent=2, ensure_ascii=False) self.logger.info(f"💾 模型注册表已保存: {registry_path}") return True except Exception as e: self.logger.error(f"❌ 保存模型注册表失败: {str(e)}") return False def register_model(self, model_name: str, model_path: str, model_type: str = "text", adapter_config: Optional[dict] = None) -> bool: """ 注册模型 """ # 检查模型是否存在 exists, is_local = self._check_model_exists(model_path) if not exists: self.logger.error(f"❌ 模型路径不可访问: {model_path}") return False # 计算校验和 checksum = "unknown" if is_local: try: checksum = self._calculate_checksum(model_path) except Exception as e: self.logger.warning(f"⚠️ 无法计算校验和: {str(e)}") checksum = "error" # 添加到注册表 self._persistent_registry[model_name] = { "path": model_path, "type": model_type, "status": "unloaded", "checksum": checksum, "last_accessed": time.time(), "adapter": adapter_config, "is_local": is_local } self.logger.info(f"✅ 模型注册成功: {model_name} ({model_type})") self._save_registry() return True def _check_model_exists(self, model_path: str) -> Tuple[bool, bool]: """检查模型路径是否有效""" # 如果是HuggingFace模型ID if is_valid_hf_id(model_path): # 使用路径工具验证 self.logger.info(f"🔍 检测到HuggingFace模型ID: {model_path}") return True, False # 检查本地路径 abs_path = normalize_path(model_path) # 路径规范化 if os.path.exists(abs_path): return True, True # 尝试相对路径 if os.path.exists(model_path): return True, True return False, False def _calculate_checksum(self, model_path: str) -> str: """计算模型校验和""" abs_path = normalize_path(model_path) # 路径规范化 if os.path.isdir(abs_path): sha256 = hashlib.sha256() key_files = ["pytorch_model.bin", "model.safetensors", "config.json"] for root, _, files in os.walk(abs_path): for file in files: if file in key_files: file_path = os.path.join(root, file) with open(file_path, &#39;rb&#39;) as f: while chunk := f.read(8192): sha256.update(chunk) return sha256.hexdigest() # 单个模型文件 with open(abs_path, &#39;rb&#39;) as f: return hashlib.sha256(f.read()).hexdigest() def load_model(self, model_name: str, force_reload: bool = False) -> Tuple[bool, Any]: """ 加载模型到内存 """ if model_name not in self._persistent_registry: self.logger.error(f"❌ 模型未注册: {model_name}") return False, None model_info = self._persistent_registry[model_name] model_path = model_info["path"] abs_path = normalize_path(model_path) if model_info.get("is_local", True) else model_path # 路径规范化 # 如果模型已加载且不需要强制重载 if model_name in self.loaded_models and not force_reload: self.logger.info(f"📦 模型已在内存中: {model_name}") model_info["last_accessed"] = time.time() return True, self.loaded_models[model_name] # 检查内存占用 if len(self.loaded_models) >= self.max_models_in_memory: self._unload_least_recently_used() # 实际加载模型 try: self.logger.info(f"🔄 加载模型: {model_name} ({model_info[&#39;type&#39;]})") model_type = model_info["type"] if model_type == "text": model = self._load_text_model(model_info, abs_path) elif model_type == "image": model = self._load_image_model(model_info, abs_path) elif model_type == "audio": model = self._load_audio_model(model_info, abs_path) else: self.logger.error(f"❌ 不支持的模型型: {model_type}") return False, None # 更状态 self.loaded_models[model_name] = model model_info["status"] = "loaded" model_info["last_accessed"] = time.time() self._save_registry() self.logger.info(f"✅ 模型加载成功: {model_name}") return True, model except ImportError as e: self.logger.error(f"❌ 缺失依赖库: {str(e)}") return False, None except Exception as e: self.logger.error(f"❌ 模型加载失败: {model_name}, 路径: {abs_path}, 错误: {str(e)}") model_info["status"] = "error" return False, None def _load_text_model(self, model_info: dict, model_path: str) -> Any: """加载文本模型""" try: from transformers import AutoModelForCausalLM, AutoTokenizer except ImportError: self.logger.error("❌ transformers库未安装") raise RuntimeError("transformers not installed") self.logger.debug(f"🔧 加载文本模型: {model_path}") device = "cuda" if self.use_gpu else "cpu" try: tokenizer = AutoTokenizer.from_pretrained(model_path, cache_dir=self.cache_dir) model = AutoModelForCausalLM.from_pretrained( model_path, cache_dir=self.cache_dir, device_map=device if self.use_gpu else None ) return { "model": model, "tokenizer": tokenizer, "info": model_info } except OSError as e: self.logger.error(f"❌ 加载失败: 请检查路径 &#39;{model_path}&#39; 是否正确") fallback_path = self._try_find_model_path(model_path) if fallback_path: self.logger.warning(f"⚠️ 尝试备用路径: {fallback_path}") return self._load_text_model(model_info, fallback_path) raise except Exception as e: self.logger.error(f"❌ 加载过程中发生意外错误: {str(e)}") raise def _try_find_model_path(self, original_path: str) -> Optional[str]: """尝试找到备用模型路径""" # 1. 检查项目内的模型目录 project_models = os.path.join(os.getcwd(), "local_models", os.path.basename(original_path)) if os.path.exists(project_models): return project_models # 2. 检查缓存目录 cache_path = os.path.join(self.cache_dir, "models", os.path.basename(original_path)) if os.path.exists(cache_path): return cache_path # 3. 尝试父目录 parent_path = os.path.join(os.path.dirname(os.getcwd()), os.path.basename(original_path)) if os.path.exists(parent_path): return parent_path return None def unload_model(self, model_name: str = None) -> bool: """卸载模型""" if model_name is None: self.logger.info("卸载所有模型") for name in list(self.loaded_models.keys()): if not self._unload_single_model(name): self.logger.error(f"❌ 卸载模型失败: {name}") return True return self._unload_single_model(model_name) def _unload_single_model(self, model_name: str) -> bool: """卸载单个模型""" if model_name not in self.loaded_models: self.logger.warning(f"⚠️ 模型未加载: {model_name}") return False try: # 显式释放模型资源 model_data = self.loaded_models[model_name] if "model" in model_data: del model_data["model"] if "tokenizer" in model_data: del model_data["tokenizer"] # 删除引用调用垃圾回收 del self.loaded_models[model_name] gc.collect() # 如果使用GPU,额外清理CUDA缓存 if self.use_gpu: try: import torch torch.cuda.empty_cache() self.logger.debug("♻️ 已清理GPU缓存") except ImportError: pass # 更注册表状态 if model_name in self._persistent_registry: self._persistent_registry[model_name]["status"] = "unloaded" self._save_registry() self.logger.info(f"🗑️ 模型已卸载: {model_name}") return True except Exception as e: self.logger.error(f"❌ 卸载模型失败: {model_name}, 错误: {str(e)}") return False def _unload_least_recently_used(self): """卸载最近最少使用的模型""" if not self.loaded_models: return # 找到最近最少使用的模型 lru_model = None lru_time = float(&#39;inf&#39;) for model_name in self.loaded_models: last_accessed = self._persistent_registry[model_name].get("last_accessed", 0) if last_accessed < lru_time: lru_time = last_accessed lru_model = model_name if lru_model: self.logger.info(f"♻️ 卸载最近最少使用的模型: {lru_model}") self._unload_single_model(lru_model) def _load_image_model(self, model_info: dict, model_path: str) -> Any: """加载图像模型""" self.logger.info(f"🖼️ 加载图像模型: {model_path}") try: # 示例:使用diffusers库加载SDXL模型 from diffusers import StableDiffusionPipeline import torch device = "cuda" if self.use_gpu and torch.cuda.is_available() else "cpu" pipeline = StableDiffusionPipeline.from_pretrained( model_path, cache_dir=self.cache_dir, torch_dtype=torch.float16 if device == "cuda" else torch.float32 ).to(device) return { "pipeline": pipeline, "info": model_info } except ImportError: self.logger.error("❌ diffusers库未安装,无法加载图像模型") raise except Exception as e: self.logger.error(f"❌ 图像模型加载失败: {str(e)}") raise def _load_audio_model(self, model_info: dict, model_path: str) -> Any: """加载音频模型""" self.logger.info(f"🎵 加载音频模型: {model_path}") try: # 示例:加载语音识别模型 from transformers import AutoProcessor, AutoModelForSpeechSeq2Seq import torch device = "cuda" if self.use_gpu and torch.cuda.is_available() else "cpu" processor = AutoProcessor.from_pretrained(model_path, cache_dir=self.cache_dir) model = AutoModelForSpeechSeq2Seq.from_pretrained( model_path, cache_dir=self.cache_dir, torch_dtype=torch.float16 if device == "cuda" else torch.float32 ).to(device) return { "model": model, "processor": processor, "info": model_info } except ImportError: self.logger.error("❌ transformers库未安装,无法加载音频模型") raise except Exception as e: self.logger.error(f"❌ 音频模型加载失败: {str(e)}") raise def shutdown(self): """关闭模型管理器""" self.logger.info("🛑 关闭模型管理器...") self.unload_model() # 卸载所有模型 # 清理缓存(可选) self.logger.info("✅ 模型管理器已关闭") “ 4.”# E:\AI_System\agent\diagnostic_system.py import logging import psutil import time import random class DiagnosticSystem: def init(self): self.logger = logging.getLogger(“DiagnosticSystem”) def check_modules(self): """检查核心模块状态""" results = { "cognitive_system": self._check_cognitive(), "environment_interface": self._check_environment(), "affective_system": self._check_affective(), "system_resources": self._check_resources() } return results def _check_cognitive(self): try: # 检查认知系统模块 from .cognitive_architecture import CognitiveSystem # 模拟些额外信息 return { "status": "✅ 正常运行", "version": CognitiveSystem.VERSION, "last_heartbeat": time.time() - random.randint(1, 10) } except Exception as e: return {"status": "❌ 异常", "error": str(e)} def _check_environment(self): try: # 检查环境接口模块 from .environment_interface import EnvironmentInterface return { "status": "✅ 正常运行", "connection": "active", "last_ping": time.time() - random.randint(1, 5) } except Exception as e: return {"status": "❌ 异常", "error": str(e)} def _check_affective(self): try: # 检查情感系统模块 from .affective_system import AffectiveSystem return { "status": "✅ 正常运行", "emotion_state": "neutral", "intensity": random.randint(1, 100) } except Exception as e: return {"status": "❌ 异常", "error": str(e)} def _check_resources(self): """检查系统资源使用情况""" try: return { "cpu": f"{psutil.cpu_percent()}%", "memory": f"{psutil.virtual_memory().percent}%", "gpu": self._get_gpu_status(), "disk": self._get_disk_usage() } except Exception as e: return {"error": f"资源检查失败: {str(e)}"} def _get_gpu_status(self): try: import gpustat stats = gpustat.new_query() return [{ "id": gpu.index, "utilization": f"{gpu.utilization}%", "memory": f"{gpu.memory_used}/{gpu.memory_total}MB", "temperature": f"{gpu.temperature}°C" } for gpu in stats.gpus] except ImportError: return "⚠️ gpustat 未安装" except Exception as e: return f"❌ GPU检测失败: {str(e)}" def _get_disk_usage(self): try: disk = psutil.disk_usage(&#39;/&#39;) return { "total": f"{disk.total // (1024 ** 3)}GB", "used": f"{disk.used // (1024 ** 3)}GB", "free": f"{disk.free // (1024 ** 3)}GB", "percent": f"{disk.percent}%" } except Exception as e: return f"❌ 磁盘检测失败: {str(e)}" “ 4.organize_repo.bat 这个你让我的文件是干嘛的?我的仓库只需要整理 不需要删除 你能理解吗?你要是可以整理 能帮我把E:\ai_temp里面的”wechat translate 2025-08-09 141611 696.pngwechat translate 2025-08-09 170304 577.pngwechat translate 2025-08-10 024015 869.pngwechat translate 2025-08-10 115402 030.pngwechat translate 2025-08-10 120045 852.pngwechat translate 2025-08-10 121801 405.pngwechat translate 2025-08-10 121939 750.pngwechat translate 2025-08-10 164544 700.pngwechat translate 2025-08-10 164738 407.pngwechat translate 2025-08-10 183846 043.pngwechat translate 2025-08-17 014313 045.pngwechat translate 2025-08-17 014801 635.pngwechat translate 2025-08-17 014813 557.pngwechat translate 2025-08-17 014824 680.pngwechat translate 2025-08-17 014840 935.png“”wechat 2025-08-17 014823 645.pngwechat 2025-08-17 014839 552.png wechat 2025-08-17 023912 994.png wechat 2025-08-17 104544 487.png wechat 2025-08-17 104802 038.png wechat 2025-08-17 105923 918.png wechat 2025-08-17 110036 545.png wechat 2025-08-17 112641 042.png wechat 2025-08-17 112711 884.png wechat 2025-08-17 124218 228.png“”b0a50e77-4abb-47bc-b627-c8447dfc0cdb.tmpb0e7b665-9e1b-49b1-b4b6-b82ee9d9c002.tmpb6d33607-1696-4c04-80f5-38baa97cf874.tmpb34d0fed-e3a3-457c-aa5d-bc5c05196d68.tmpb982a35d-8e2b-4357-bf5a-7d8379bde852.tmpb4950b49-3ef1-452f-a121-481149d634d9.tmpb8608a9f-1605-411a-890b-f4d5ac3e13d5.tmpb069211d-c01b-4ddb-b2a4-ca0cc571b894.tmpbc66bff3-e877-4971-b1b8-bccdbd475364.tmpbc9044ce-6842-411c-bfb8-1ddb93efa2bd.tmpc1fa1b81-defb-49cb-adac-7895f1c7ef2f.tmpc17ebdcc-3e62-46f3-ad70-23fb637a01b9.tmpc83c7258-212e-42b1-8305-b91c52a39612.tmpc93d0105-dbe5-4e4b-ab16-ea9179f7659d.tmpc0453cd5-9cf4-46e3-b798-fa625d576a4c.tmpc528dfe9-0091-480a-9d19-bd2f196bf4db.tmpc880a954-fd81-4a05-a7d0-71fafb05c76c.tmpc8654c92-8e10-49c5-8e74-79fe9692a262.tmp“这些文件 都整理好吗?它们太多了,我不想删除 只想整理 我的空间完全够用 5.我发你的三个源文件 你还是改好了给我吧 你让我改我不会,其他的 都按你说的弄完了
08-31
# -*- coding: utf-8 -*- import tkinter as tk from tkinter import ttk, filedialog, messagebox import socket import threading import os from datetime import datetime from tkinter.font import Font # 移除默认端口号定义,因为端口号将由用户输入 BUFFER_SIZE = 8192 # File transfer buffer size class P2PApp: def __init__(self): self.root = tk.Tk() self.root.title("P2P Communication Tool v1.1") self.encoding = &#39;utf-8&#39; # Unified encoding # Set the font that supports Chinese # self.root.option_add("*Font", "NSimSun 10") self.system_font = Font(family="WenQuanYi Micro Hei", size=10) # 网络参数设置 self.local_ip = self.get_local_ip()#获取存储本地设备的 IP 地址。 self.server_socket = None#初始化服务器套接字变量。 self.client_connections = [] # 用于存储所有客户端连接 # Multithreading control self.server_running = True # 程序启动即作为服务端运行 self.lock = threading.Lock() # 线程锁 # 接收文件的文件夹 self.received_files_folder = "received_files" if not os.path.exists(self.received_files_folder): os.makedirs(self.received_files_folder) # 增昵称相关 self.nickname = "User" self.create_nickname_widget() # GUI initialization self.create_widgets() # 绑定回车键 self.msg_entry.bind("<Return>", lambda event: self.send_message()) # 启动服务端监听 self.start_server() # 配置消息颜色标签 self.history_text.tag_configure(&#39;send&#39;, foreground=&#39;black&#39;) self.history_text.tag_configure(&#39;receive&#39;, foreground=&#39;blue&#39;) # 关闭窗口时销毁资源 self.root.protocol("WM_DELETE_WINDOW", self.on_close) def create_nickname_widget(self): nickname_frame = ttk.LabelFrame(self.root, text="Nickname") nickname_frame.grid(row=0, column=0, padx=10, pady=5, sticky="ew") ttk.Label(nickname_frame, text="Nickname:", font=self.system_font).grid(row=0, column=0, sticky="w", padx=5) self.nickname_entry = ttk.Entry(nickname_frame, width=20) self.nickname_entry.insert(0, self.nickname) self.nickname_entry.grid(row=0, column=1, padx=5) self.change_nickname_btn = ttk.Button( nickname_frame, text="Change Nickname", command=self.change_nickname ) self.change_nickname_btn.grid(row=0, column=2, padx=5) def change_nickname(self): new_nickname = self.nickname_entry.get() if new_nickname: self.nickname = new_nickname def create_widgets(self): # IP address area ip_frame = ttk.LabelFrame(self.root, text="Network Configuration") ip_frame.grid(row=1, column=0, padx=10, pady=5, sticky="ew") ttk.Label(ip_frame, text="Local IP:", font=self.system_font).grid(row=0, column=0, sticky="w", padx=5) self.local_ip_label = ttk.Label(ip_frame, text=self.local_ip, width=20) self.local_ip_label.grid(row=0, column=1, padx=5) ttk.Label(ip_frame, text="Target IP:").grid(row=1, column=0, sticky="w", padx=5) self.target_ip_entry = ttk.Entry(ip_frame, width=20) self.target_ip_entry.insert(0, "172.16.118.0") # 设置目标 IP 的初始默认值 self.target_ip_entry.grid(row=1, column=1, padx=5) ttk.Label(ip_frame, text="Target Port:").grid(row=1, column=2, sticky="w", padx=5) self.target_port_entry = ttk.Entry(ip_frame, width=8) self.target_port_entry.insert(0, "12346") # 默认目标端口号 self.target_port_entry.grid(row=1, column=3, padx=5) # 去掉 Connect Client 按钮,换成测试按钮 btn_frame = ttk.Frame(ip_frame) btn_frame.grid(row=0, column=4, rowspan=2, padx=10, sticky="ns") self.test_btn = ttk.Button( btn_frame, text="Test Connection", command=self.test_connection, width=12 ) self.test_btn.grid(row=0, column=0, pady=2) # Message history area history_frame = ttk.LabelFrame(self.root, text="Message History") history_frame.grid(row=2, column=0, padx=10, pady=5, sticky="nsew") self.history_text = tk.Text( history_frame, height=15, state=&#39;disabled&#39;, wrap=tk.WORD ) scrollbar = ttk.Scrollbar(history_frame, command=self.history_text.yview) self.history_text.configure(yscrollcommand=scrollbar.set) self.history_text.grid(row=0, column=0, sticky="nsew") scrollbar.grid(row=0, column=1, sticky="ns") # Input area input_frame = ttk.LabelFrame(self.root, text="Message Input") input_frame.grid(row=3, column=0, padx=10, pady=5, sticky="ew") self.msg_entry = ttk.Entry(input_frame, width=40) self.msg_entry.grid(row=0, column=0, padx=5) self.send_btn = ttk.Button( input_frame, text="Send Message", command=self.send_message ) self.send_btn.grid(row=0, column=1, padx=2) self.file_btn = ttk.Button( input_frame, text="Send File", command=self.send_file ) self.file_btn.grid(row=0, column=2, padx=2) # Layout configuration self.root.columnconfigure(0, weight=1) self.root.rowconfigure(2, weight=1) def show_connection_status(self): # Example message pop-up window messagebox.showinfo("Connection Status", "Connection established successfully!") def get_local_ip(self): """获取本地设备的 IP 地址""" try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(("8.8.8.8", 80)) # Connect to a public DNS to get the IP ip = s.getsockname()[0] s.close() return ip except Exception as e: messagebox.showerror("Error", f"Failed to get local IP: {str(e)}") return "127.0.0.1" def start_server(self): """启动服务端监听""" max_retries = 10 # 最大重试次数 retry_count = 0 while retry_count < max_retries: try: # 使用默认服务端端口号 local_server_port = 12346 + retry_count self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 设置 SO_REUSEADDR 选项 self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.server_socket.bind((self.local_ip, local_server_port)) self.server_socket.listen(5) server_thread = threading.Thread(target=self.server_listener, daemon=True) server_thread.start() self.update_history(f"Server started on port {local_server_port}", is_send=False) return except OSError as e: if e.errno == 98: # Address already in use retry_count += 1 next_port = 12346 + retry_count self.update_history(f"Port {local_server_port} is already in use. Retrying with port {local_server_port + 1}...") else: messagebox.showerror("Error", f"Failed to start the server: {str(e)}") return messagebox.showerror("Error", "Failed to start the server after multiple retries.") def server_listener(self): """服务器监听循环,持续接受客户端连接""" while self.server_running: try: conn, addr = self.server_socket.accept() # self.update_history(f"Connection from {addr}", is_send=False) self.client_connections.append(conn) # 添加连接到列表 client_thread = threading.Thread( target=self.handle_connection, args=(conn,), daemon=True ) client_thread.start() except OSError: break # Exception when closing normally def handle_connection(self, conn): """Handle client connections""" with conn: while True: try: data = conn.recv(BUFFER_SIZE) if not data: break self.process_received_data(data, conn.getpeername()) except ConnectionResetError: break except Exception as e: self.update_history(f"Error receiving data: {str(e)}", is_send=False) break # 连接关闭时从列表中移除 if conn in self.client_connections: self.client_connections.remove(conn) def test_connection(self): """测试与目标 IP 地址和端口的连接""" target_ip = self.target_ip_entry.get() try: target_port = int(self.target_port_entry.get()) except ValueError: messagebox.showerror("Error", "Please enter a valid target port number.") return if not target_ip: messagebox.showwarning("Warning", "Please enter the target IP address.") return try: test_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) test_socket.settimeout(2) test_socket.connect((target_ip, target_port)) test_socket.close() messagebox.showinfo("Test result", "The connection is successful!") except Exception as e: messagebox.showerror("Test result", f"The connection fails: {str(e)}") def send_message(self): """Send a text message""" message = self.msg_entry.get() if not message: return target_ip = self.target_ip_entry.get() try: target_port = int(self.target_port_entry.get()) except ValueError: messagebox.showerror("Error", "Please enter a valid target port number.") return if not target_ip: messagebox.showwarning("Warning", "Please enter the target IP address.") return try: # Construct the protocol header header = f"MSG{datetime.now().strftime(&#39;%H:%M:%S&#39;)}".ljust(12) full_msg = header.encode() + f"{self.nickname}: {message}".encode(&#39;utf-8&#39;) # 的连接 client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect((target_ip, target_port)) client_socket.sendall(full_msg) client_socket.close() self.update_history(f"{self.nickname}: {message}") self.msg_entry.delete(0, tk.END) # 广播消息给所有连接的客户端,排除自身 with self.lock: connections_to_remove = [] for conn in self.client_connections: try: # 检查是否为自身连接 if conn.getpeername() != (target_ip, target_port): conn.sendall(full_msg) except OSError as e: if e.errno == 32: # Broken pipe connections_to_remove.append(conn) self.update_history(f"Connection to client broken: {conn.getpeername()}", is_send=False) else: self.update_history(f"Error sending message to client: {str(e)}", is_send=False) # 移除断开的连接 for conn in connections_to_remove: if conn in self.client_connections: self.client_connections.remove(conn) except Exception as e: messagebox.showerror("Error", f"Failed to send the message: {str(e)}") def send_file(self): """Send a file""" file_path = filedialog.askopenfilename() if not file_path: return if os.path.isdir(file_path): messagebox.showerror("Error", "Sending folders is not supported.") return target_ip = self.target_ip_entry.get() try: target_port = int(self.target_port_entry.get()) except ValueError: messagebox.showerror("Error", "Please enter a valid target port number.") return if not target_ip: messagebox.showwarning("Warning", "Please enter the target IP address.") return try: filename = os.path.basename(file_path) filesize = os.path.getsize(file_path) # Construct the file header header = f"FILE:{filename}:{filesize}".ljust(12).encode() # 的连接 client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect((target_ip, target_port)) client_socket.send(header) with open(file_path, &#39;rb&#39;) as f: while chunk := f.read(BUFFER_SIZE): client_socket.send(chunk) client_socket.close() self.update_history(f"File sent: {filename}") # 广播文件给所有连接的客户端,排除自身 with self.lock: connections_to_remove = [] for conn in self.client_connections: try: # 检查是否为自身连接 if conn.getpeername() != (target_ip, target_port): conn.send(header) f.seek(0) while chunk := f.read(BUFFER_SIZE): conn.send(chunk) except OSError as e: if e.errno == 32: # Broken pipe connections_to_remove.append(conn) self.update_history(f"Connection to client broken: {conn.getpeername()}", is_send=False) else: self.update_history(f"Error sending file to client: {str(e)}", is_send=False) # 移除断开的连接 for conn in connections_to_remove: if conn in self.client_connections: self.client_connections.remove(conn) except Exception as e: messagebox.showerror("Error", f"Failed to send the file: {str(e)}") def process_received_data(self, data, address): """Process the received data (general method)""" try: # Parse the protocol header header = data[:12].decode().strip() # Assume the header length is 12 bytes content = data[12:] if header.startswith("FILE"): parts = header.split(&#39;:&#39;) # File transfer protocol if len(parts) == 3: _, filename, filesize = header.split(&#39;:&#39;) self.save_file(content, filename, int(filesize), address) self.update_history(f"Received file: {filename} from {address}", is_send=False) else: self.update_history(f"Header format error: {header}", is_send=False) else: # Ordinary message message = content.decode(&#39;utf-8&#39;) self.update_history(f"{message}", is_send=False) except Exception as e: self.update_history(f"Data parsing error: {str(e)}", is_send=False) def save_file(self, data, filename, filesize, address): """Save the received file""" save_path = os.path.join(self.received_files_folder, filename) try: with open(save_path, &#39;wb&#39;) as f: f.write(data) remaining = filesize - len(data) while remaining > 0: data = self.client_socket.recv(BUFFER_SIZE) f.write(data) remaining -= len(data) self.update_history(f"File {filename} from {address} saved successfully.", is_send=False) except Exception as e: self.update_history(f"Error saving file {filename} from {address}: {str(e)}", is_send=False) def update_history(self, content, is_send=True): """Update the message history (thread-safe)""" def _update(): self.history_text.configure(state=&#39;normal&#39;) timestamp = datetime.now().strftime("[%H:%M:%S] ") tag = &#39;send&#39; if is_send else &#39;receive&#39; self.history_text.insert(&#39;end&#39;, timestamp + content + &#39;\n&#39;, tag) self.history_text.configure(state=&#39;disabled&#39;) self.history_text.see(tk.END) # Update the interface through the main thread self.root.after(0, _update) def on_close(self): """关闭窗口时销毁资源""" self.server_running = False if self.server_socket: try: self.server_socket.close() except OSError: pass for conn in self.client_connections: try: conn.close() except OSError: pass self.root.destroy() def run(self): """Run the main program""" self.root.mainloop() if __name__ == "__main__": app = P2PApp() app.run() 修改代码:目前的代码不能传输照片等文件。修改代码使其能够传输文件除了文件夹。将接收到的文件保存。在对话框只显示文件
05-13
【四轴飞行器】非线性三自由度四轴飞行器模拟器研究(Matlab代码实现)内容概要:本文围绕非线性三自由度四轴飞行器模拟器的研究展开,重点介绍了基于Matlab的模与仿真方法。通过对四轴飞行器的动力学特性进行分析,构了非线性状态空间模型,实现了姿态与位置的动态模拟。研究涵盖了飞行器运动方程的立、控制系统设计及数值仿真验证等环节,突出非线性系统的精确模与仿真优势,有助于深入理解飞行器在复杂工况下的行为特征。此外,文中还提到了多种配套技术如PID控制、状态估计与路径规划等,展示了Matlab在航空航天仿真中的综合应用能力。; 适合人群:具备定自动控制理论基础和Matlab编程能力的高校学生、科研人员及从事无人机系统开发的工程技术人员,尤其适合研究生及以上层次的研究者。; 使用场景及目标:①用于四轴飞行器控制系统的设计与验证,支持算法快速原型开发;②作为教学工具帮助理解非线性动力学系统模与仿真过程;③支撑科研项目中对飞行器姿态控制、轨迹跟踪等问题的深入研究; 阅读议:议读者结合文中提供的Matlab代码进行实践操作,重点关注动力学模与控制模块的实现细节,同时可延伸学习文档中提及的PID控制、状态估计等相关技术内容,以全面提升系统仿真与分析能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值