Unity网络开发基础 —— 实践小项目

概述

接Unity网络开发基础

导入基础知识中的代码

需求分析

手动写Handler类

手动书写消息池

using GamePlayer;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 消息池中 主要是用于 注册 ID和消息类型以及消息处理器类型的映射关系
/// 方便我们获取对象 进行反序列化和消息逻辑处理
/// </summary>
public class MsgPool 
{//记录消息类型和ID的映射关系private Dictionary<int, Type> messages = new Dictionary<int, Type>();//记录消息处理器类型和ID的映射关系private Dictionary<int, Type> handlers = new Dictionary<int, Type>();public MsgPool(){//在构造函数中进行 注册 注册映射关系Register(1001, typeof(PlayerMsg), typeof(PlayerMsgHandler));//后面继续添加消息类}private void Register(int id, Type messageType, Type handlerType){messages.Add(id, messageType);handlers.Add(id, handlerType);}/// <summary>/// 根据ID 得到一个指定的消息类对象/// </summary>/// <param name="id"></param>/// <returns></returns>public BaseMsg GetMessage(int id){if (!messages.ContainsKey(id))return null;return Activator.CreateInstance(messages[id]) as BaseMsg;}/// <summary>/// 根据ID 得到一个指定的消息处理类对象/// </summary>/// <param name="id"></param>/// <returns></returns>public BaseHandler GetHandler(int id){if (!handlers.ContainsKey(id))return null;return Activator.CreateInstance(handlers[id]) as BaseHandler;}}

工具生成Handler

工具生成消息池

源码

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using UnityEngine;namespace GamePlayer
{public enum E_Player_Type{Main,Other,}public class PlayerTest : BaseData{public List<int> list;public Dictionary<int, string> dic;public int[] arrays;public E_Player_Type type;public PlayerData player;public override int GetByteNum(){int num = 0;num += 4; //list.Countfor (int i = 0; i < list.Count; i++){num += 4;}num += 4; //dic.Countforeach (int key in dic.Keys){num += 4;//key所占的字节数num += 4;//value 字符串长度 占的字节数num += Encoding.UTF8.GetByteCount(dic[key]);}num += 4; //arrays.Length 数组长度for (int i = 0; i < arrays.Length; i++){num += 4;}num += 4; //枚举 用int来存num += player.GetByteNum(); //PlayerDatareturn num;}public override int Reading(byte[] bytes, int beginIndex = 0){int index = beginIndex;//反序列化 listlist = new List<int>();short listCount = ReadShort(bytes, ref index);            for (int i = 0; i < listCount; i++){list.Add(ReadInt(bytes, ref index));}//dicdic = new Dictionary<int, string>();short dicCount = ReadShort(bytes, ref index);            for (int i = 0; i < dicCount; i++){dic.Add(ReadInt(bytes, ref index), ReadString(bytes, ref index));}//arraysint arrayLength = ReadShort(bytes, ref index);arrays = new int[arrayLength];for (int i = 0; i < arrayLength; i++){arrays[i] = ReadInt(bytes, ref index);}//枚举type = (E_Player_Type)ReadInt(bytes, ref index);//自定义类型player = ReadData<PlayerData>(bytes, ref index);return index - beginIndex;}public override byte[] Writing(){//固定内容int index = 0;byte[] bytes = new byte[GetByteNum()];//可变的 是根据成员变量来决定如何拼接的//存储 list的长度WriteShort(bytes, (short)list.Count, ref index);for (int i = 0; i < list.Count; i++){WriteInt(bytes, list[i], ref index);}//存储 dic//先长度WriteShort(bytes, (short)dic.Count, ref index);foreach (int key in dic.Keys){WriteInt(bytes, key, ref index);WriteString(bytes, dic[key], ref index);}//存储 数组WriteShort(bytes, (short)arrays.Length, ref index);for (int i = 0; i < arrays.Length; i++){WriteInt(bytes, arrays[i], ref index);}//存储 枚举 (我们用一个 int 来存储枚举)type 是一个枚举类型WriteInt(bytes, Convert.ToInt32(type), ref index);//存储 自定义数据结构类WriteData(bytes, player, ref index);//固定内容return bytes;}}
}public class GenerateCSharp 
{//协议保存路径private string SAVE_PATH = Application.dataPath + "/Scripts/Protocol/";//生成枚举public void GenerateEnum(XmlNodeList nodes){//生成枚举脚本的逻辑string namespaceStr = "";string enumNameStr = "";string fieldStr = "";foreach (XmlNode enumNode in nodes){//获取命名空间配置信息namespaceStr = enumNode.Attributes["namespace"].Value;//获取枚举名配置信息enumNameStr = enumNode.Attributes["name"].Value;//获取所有的字段节点 然后进行字符串拼接XmlNodeList enumFields = enumNode.SelectNodes("field");//清空上一次的数据fieldStr = "";foreach (XmlNode enumField in enumFields){fieldStr += "\t\t" + enumField.Attributes["name"].Value;if (enumField.InnerText != "")fieldStr += " = " + enumField.InnerText;fieldStr += ",\r\n";}//对所有可变的内容进行拼接string enumStr = $"namespace {namespaceStr}\r\n" + "{\r\n" + $"\tpublic enum {enumNameStr}\r\n" +"\t{\r\n" +$"{fieldStr}" + "\t}\r\n" + "}";//保存文件的路径string path = SAVE_PATH + namespaceStr + "/Enum/";//如果不存在该文件夹 则创建if (!Directory.Exists(path)){Directory.CreateDirectory(path);}//字符串保存 存储为枚举脚本文件//参数一:文件名//参数二:转换成string 的 数据File.WriteAllText(path + enumNameStr + ".cs", enumStr);}Debug.Log("枚举生成结束");}//生成数据结构类public void GenerateData(XmlNodeList nodes){string namespaceStr = "";string classNameStr = "";string fieldStr = "";//将 GetBytesNum方法 写成字符串string getByteNumStr = "";// 将 Writing方法 写成字符串string writingStr = "";//将 Reading方法 写成字符串string readingStr = "";foreach (XmlNode dataNode in nodes){//命名空间namespaceStr = dataNode.Attributes["namespace"].Value;//类名classNameStr = dataNode.Attributes["name"].Value;//读取所有字段节点XmlNodeList fields = dataNode.SelectNodes("field");//通过这个方法进行成员变量声明的拼接 返回拼接结果fieldStr = GetFieldStr(fields);//通过某个方法 对GetBytesNum函数中的字符串内容进行拼接 返回结果getByteNumStr = GetGetBytesNumStr(fields);//通过某个方法 对Writing函数中的字符串内容进行拼接 返回结果writingStr = GetWritingStr(fields);//通过某个方法 对Reading函数中的字符串内容进行拼接 返回结果readingStr = GetReadingStr(fields);string dataStr = "using System.Collections.Generic;\r\n" +"using System.Text;\r\n" +"using System;\r\n\r\n" + $"namespace {namespaceStr}\r\n" +"{\r\n" +$"\tpublic class {classNameStr} : BaseData\r\n" +"\t{\r\n" +$"{fieldStr}\r\n" + "\t\tpublic override int GetByteNum()\r\n" + "\t\t{\r\n" + "\t\t\tint num = 0;\r\n" + $"{getByteNumStr}" + "\t\t\treturn num;\r\n" + "\t\t}\r\n\r\n" + "\t\tpublic override byte[] Writing()\r\n" + "\t\t{\r\n" + "\t\t\tint index = 0;\r\n" + "\t\t\tbyte[] bytes = new byte[GetByteNum()];\r\n" + $"{writingStr}" + "\t\t\treturn bytes;\r\n" + "\t\t}\r\n\r\n" +"\t\tpublic override int Reading(byte[] bytes, int beginIndex = 0)\r\n" +"\t\t{\r\n" +"\t\t\tint index = beginIndex;\r\n" +                                        $"{readingStr}" +"\t\t\treturn index - beginIndex;\r\n" +"\t\t}\r\n\r\n" +"\t}\r\n" +"}";//保存为 脚本对象//保存文件的路径string path = SAVE_PATH + namespaceStr + "/Data/";//如果没有该路径 就创建if (!Directory.Exists(path))Directory.CreateDirectory(path);//字符串保存 存储为数据结构类脚本File.WriteAllText(path + classNameStr + ".cs", dataStr);}Debug.Log("数据结构类生成结束");}//生成消息类public void CenerateMsg(XmlNodeList nodes){string namespaceStr = "";string classNameStr = "";string idStr = "";string fieldStr = "";//将 GetBytesNum方法 写成字符串string getByteNumStr = "";// 将 Writing方法 写成字符串string writingStr = "";//将 Reading方法 写成字符串string readingStr = "";foreach (XmlNode dataNode in nodes){//命名空间namespaceStr = dataNode.Attributes["namespace"].Value;//类名classNameStr = dataNode.Attributes["name"].Value;//消息ididStr = dataNode.Attributes["id"].Value;//读取所有字段节点XmlNodeList fields = dataNode.SelectNodes("field");//通过这个方法进行成员变量声明的拼接 返回拼接结果fieldStr = GetFieldStr(fields);//通过某个方法 对GetBytesNum函数中的字符串内容进行拼接 返回结果getByteNumStr = GetGetBytesNumStr(fields);//通过某个方法 对Writing函数中的字符串内容进行拼接 返回结果writingStr = GetWritingStr(fields);//通过某个方法 对Reading函数中的字符串内容进行拼接 返回结果readingStr = GetReadingStr(fields);string dataStr = "using System.Collections.Generic;\r\n" +"using System.Text;\r\n" +"using System;\r\n\r\n" +$"namespace {namespaceStr}\r\n" +"{\r\n" +$"\tpublic class {classNameStr} : BaseMsg\r\n" +"\t{\r\n" +$"{fieldStr}\r\n" +"\t\tpublic override int GetByteNum()\r\n" +"\t\t{\r\n" +"\t\t\tint num = 8;\r\n" + //这个8代表的是 消息ID的4个字节 + 消息体长度的4个字节$"{getByteNumStr}" +"\t\t\treturn num;\r\n" +"\t\t}\r\n\r\n" +"\t\tpublic override byte[] Writing()\r\n" +"\t\t{\r\n" +"\t\t\tint index = 0;\r\n" +"\t\t\tbyte[] bytes = new byte[GetByteNum()];\r\n" +"\t\t\tWriteInt(bytes, GetID(), ref index);\r\n" + "\t\t\tWriteInt(bytes, bytes.Length - 8, ref index);\r\n" + $"{writingStr}" +"\t\t\treturn bytes;\r\n" +"\t\t}\r\n\r\n" +"\t\tpublic override int Reading(byte[] bytes, int beginIndex = 0)\r\n" +"\t\t{\r\n" +"\t\t\tint index = beginIndex;\r\n" +$"{readingStr}" +"\t\t\treturn index - beginIndex;\r\n" +"\t\t}\r\n\r\n" +"\t\tpublic override int GetID()\r\n" +"\t\t{\r\n" +"\t\t\treturn " + idStr + ";\r\n" +"\t\t}\r\n\r\n" +"\t}\r\n" +"}";//保存为 脚本对象//保存文件的路径string path = SAVE_PATH + namespaceStr + "/Msg/";//如果没有该路径 就创建if (!Directory.Exists(path))Directory.CreateDirectory(path);//字符串保存 存储为数据结构类脚本File.WriteAllText(path + classNameStr + ".cs", dataStr);//生成处理器脚本//判断消息处理器脚本是否存在 如果存在 就不要覆盖了 避免把写过的逻辑处理代码覆盖了//如果想要改变 那就直接把没用的删了 它就会自动生成if (File.Exists(path + classNameStr + "Handler.cs"))continue;string handlerStr = $"namespace {namespaceStr}\r\n" +"{\r\n" +$"\tpublic class {classNameStr}Handler : BaseHandler\r\n" + "\t{\r\n" + "\t\tpublic override void MsgHandle()\r\n" +"\t\t{\r\n" + $"\t\t\t{classNameStr} msg = message as {classNameStr};\r\n" + "\t\t}\r\n" + "\t}\r\n" + "}\r\n";//把消息处理器类的内容保存到本地File.WriteAllText(path + classNameStr + "Handler.cs", handlerStr);}Debug.Log("消息类生成结束");}//生成消息池 主要就是ID和消息类型以及消息处理器类型的对应关系public void GenerateMsgPool(XmlNodeList nodes){List<string> ids = new List<string>();List<string> names = new List<string>();List<string> nameSpaces = new List<string>();foreach (XmlNode dataNode in nodes){//记录所有消息的IDstring id = dataNode.Attributes["id"].Value;if (!ids.Contains(id))ids.Add(id);elseDebug.LogError("存在相同ID的消息" + id);//记录所有消息的名字string name = dataNode.Attributes["name"].Value;if (!names.Contains(name))names.Add(name);elseDebug.LogError("存在相同名字的消息" + id + ",建议即使在不同命名空间中也不要要同名的信息");//获取所有消息的命名空间string msgNamespace = dataNode.Attributes["namespace"].Value;if (!nameSpaces.Contains(msgNamespace))nameSpaces.Add(msgNamespace);//获取所有消息注册相关的内容string registerStr = "";for (int i = 0; i < ids.Count; i++){registerStr += $"\t\tRegister({ids[i]}, typeof({names[i]}), typeof({names[i]}Handler));\r\n";}//获取所有需要引用的命名空间 string nameSpaceStr = "";for (int i = 0; i < nameSpaces.Count; i++){nameSpaceStr += $"using {nameSpaces[i]};\r\n";}//消息池对应的类的字符串信息string msgPoolStr = "using System;\r\n" +"using System.Collections.Generic;\r\n" +nameSpaceStr +"public class MsgPool\r\n" +"{\r\n" +"\tprivate Dictionary<int, Type> messages = new Dictionary<int, Type>();\r\n" +"\tprivate Dictionary<int, Type> handlers = new Dictionary<int, Type>();\r\n\r\n" +"\tpublic MsgPool()\r\n" +"\t{\r\n" +registerStr +"\t}\r\n" +"\tpublic void Register(int id, Type messageType, Type handlerType)\r\n" +"\t{\r\n" +"\t\tmessages.Add(id, messageType);\r\n" +"\t\thandlers.Add(id, handlerType);\r\n" +"\t}\r\n" +"\tpublic BaseMsg GetMessage(int id)\r\n" +"\t{\r\n" +"\t\tif (!messages.ContainsKey(id))\r\n" +"\t\t\treturn null;\r\n" +"\t\treturn Activator.CreateInstance(messages[id]) as BaseMsg;\r\n" +"\t}\r\n" +"\tpublic BaseHandler GetHandler(int id)\r\n" +"\t{\r\n" +"\t\tif (!handlers.ContainsKey(id))\r\n" +"\t\t\treturn null;\r\n" +"\t\treturn Activator.CreateInstance(handlers[id]) as BaseHandler;\r\n" +"\t}\r\n" +"}\r\n";//看看有没有这个路径string path = SAVE_PATH + "/Pool/";if (!Directory.Exists(path))Directory.CreateDirectory(path);//保存到本地File.WriteAllText(path + "MsgPool.cs", msgPoolStr);Debug.Log("消息池生成结束");}}/// <summary>/// 获取成员变量声明内容/// </summary>/// <param name="fields"></param>/// <returns></returns>private string GetFieldStr(XmlNodeList fields){string fieldStr = "";foreach (XmlNode field in fields){//变量类型string type = field.Attributes["type"].Value;//变量名string fieldName = field.Attributes["name"].Value;if (type == "list"){string T = field.Attributes["T"].Value;fieldStr += "\t\tpublic " + "List<" + T + "> ";}else if (type == "array"){string data = field.Attributes["data"].Value;fieldStr += "\t\tpublic " + data + "[] ";}else if(type == "dic"){string Tkey = field.Attributes["Tkey"].Value;string Tvalue = field.Attributes["Tvalue"].Value;fieldStr += "\t\tpublic " + "Dictionary<" + Tkey + ", " + Tvalue + "> ";}else if(type == "enum"){string data = field.Attributes["data"].Value;fieldStr += "\t\tpublic " + data + " ";}else{fieldStr += "\t\tpublic " + type + " ";}fieldStr += fieldName + ";\r\n";}return fieldStr;}/// <summary>/// 拼接 GetBytesNum函数的方法/// </summary>/// <param name="fields"></param>/// <returns></returns>private string GetGetBytesNumStr(XmlNodeList fields){string bytesNumStr = "";string type = "";string name = "";foreach (XmlNode field in fields){type = field.Attributes["type"].Value;name = field.Attributes["name"].Value;if (type == "list"){string T = field.Attributes["T"].Value;bytesNumStr += "\t\t\tnum += 2;\r\n"; // 2 是为了节约字节数 用一个short去存储数量信息bytesNumStr += "\t\t\tfor(int i = 0; i < " + name + ".Count; i++)\r\n";//这里使用的是 name + [i] 目的是获取 list当中的元素传入进行使用bytesNumStr += "\t\t\t\tnum += " + GetValueBytesNum(T, name + "[i]") + ";\r\n";}else if (type == "array"){string data = field.Attributes["data"].Value;bytesNumStr += "\t\t\tnum += 2;\r\n";bytesNumStr += "\t\t\tfor(int i = 0; i < " + name + ".Length; i++)\r\n";bytesNumStr += "\t\t\t\tnum += " + GetValueBytesNum(data, name + "[i]") + ";\r\n";}else if (type == "dic"){string Tkey = field.Attributes["Tkey"].Value;string Tvalue = field.Attributes["Tvalue"].Value;bytesNumStr += "\t\t\tnum += 2;\r\n";bytesNumStr += "\t\t\tforeach(" + Tkey + " key in " + name + ".Keys)\r\n";bytesNumStr += "\t\t\t{\r\n";bytesNumStr += "\t\t\t\tnum += " + GetValueBytesNum(Tkey, "key") + ";\r\n";bytesNumStr += "\t\t\t\tnum += " + GetValueBytesNum(Tvalue, name + "[key]") + ";\r\n";bytesNumStr += "\t\t\t}\r\n";}elsebytesNumStr += "\t\t\tnum += " + GetValueBytesNum(type, name) + ";\r\n";}return bytesNumStr;}//获取指定类型的字节数private string GetValueBytesNum(string type, string name){//其它类型根据需求添加switch (type){case "int":case "float":case "enum":return "4";case "bool":case "byte":return "1";case "short":return "2";case "long":case "double":return "8";case "string":return "4 + Encoding.UTF8.GetByteCount(" + name + ")";default:return name + ".GetByteNum()";}}/// <summary>/// 拼接 Writing函数的方法/// </summary>/// <param name="field"></param>/// <returns></returns>private string GetWritingStr(XmlNodeList fields){string writingStr = "";string type = "";string name = "";foreach (XmlNode field in fields){type = field.Attributes["type"].Value;name = field.Attributes["name"].Value;if (type == "list"){string T = field.Attributes["T"].Value;writingStr += "\t\t\tWriteShort(bytes, (short)" + name + ".Count, ref index);\r\n";writingStr += "\t\t\tfor(int i = 0; i < " + name + ".Count; i++)\r\n";writingStr += "\t\t\t\t" + GetFieldWritingStr(T, name + "[i]") + "\r\n";}else if(type == "array"){string data = field.Attributes["data"].Value;writingStr += "\t\t\tWriteShort(bytes, (short)" + name + ".Length, ref index);\r\n";writingStr += "\t\t\tfor(int i = 0; i < " + name + ".Length; i++)\r\n";writingStr += "\t\t\t\t" + GetFieldWritingStr(data, name + "[i]") + "\r\n";}else if (type == "dic"){string Tkey = field.Attributes["Tkey"].Value;string Tvalue = field.Attributes["Tvalue"].Value;writingStr += "\t\t\tWriteShort(bytes, (short)" + name + ".Count, ref index);\r\n";writingStr += "\t\t\tforeach(" + Tkey + " key in " + name + ".Keys)\r\n";writingStr += "\t\t\t{\r\n";writingStr += "\t\t\t\t" + GetFieldWritingStr(Tkey, "key") + "\r\n";writingStr += "\t\t\t\t" + GetFieldWritingStr(Tvalue, name + "[key]") + "\r\n";writingStr += "\t\t\t}\r\n";}else{writingStr += "\t\t\t" + GetFieldWritingStr(type, name) + "\r\n";}}return writingStr;}private string GetFieldWritingStr(string type, string name){switch (type){case "byte":return "WriteByte(bytes, " + name + ", ref index);";case "int":return "WriteInt(bytes, " + name + ", ref index);";case "short":return "WriteShort(bytes, " + name + ", ref index);";case "long":return "WriteLong(bytes, " + name + ", ref index);";case "float":return "WriteFloat(bytes, " + name + ", ref index);";case "bool":return "WriteBool(bytes, " + name + ", ref index);";case "string":return "WriteString(bytes, " + name + ", ref index);";case "enum":return "WriteInt(bytes, Convert.ToInt32(" + name + "), ref index);"; default:return "WriteData(bytes, " + name + ", ref index);";}}//private string GetReadingStr(XmlNodeList fields){string readingStr = "";string type = "";string name = "";foreach (XmlNode field in fields){type = field.Attributes["type"].Value;name = field.Attributes["name"].Value;if (type == "list"){string T = field.Attributes["T"].Value;readingStr += "\t\t\t" + name + " = new List<" + T + ">();\r\n";readingStr += "\t\t\tshort " + name + "Count = ReadShort(bytes, ref index);\r\n";readingStr += "\t\t\tfor(int i = 0; i < " + name + "Count; i++)\r\n";readingStr += "\t\t\t\t" + name + ".Add(" + GetFieldReadingStr(T) + ");\r\n";}else if (type == "array"){string data = field.Attributes["data"].Value;                readingStr += "\t\t\tshort " + name + "Length = ReadShort(bytes, ref index);\r\n";readingStr += "\t\t\t" + name + " = new " + data + "[" + name + "Length];\r\n";readingStr += "\t\t\tfor(int i = 0; i < " + name + "Length; i++)\r\n";readingStr += "\t\t\t\t" + name + "[i] = " + GetFieldReadingStr(data) + ";\r\n";}else if (type == "dic"){string Tkey = field.Attributes["Tkey"].Value;string Tvalue = field.Attributes["Tvalue"].Value;readingStr += "\t\t\t" + name + " = new Dictionary<" + Tkey + ", " + Tvalue + ">();\r\n";readingStr += "\t\t\tshort " + name + "Count = ReadShort(bytes, ref index);\r\n";readingStr += "\t\t\tfor(int i = 0; i < " + name + "Count; i++)\r\n";readingStr += "\t\t\t\t" + name + ".Add(" + GetFieldReadingStr(Tkey)+ ", " + GetFieldReadingStr(Tvalue) + ");\r\n";}else if (type == "enum"){string data = field.Attributes["data"].Value;readingStr += "\t\t\t" + name + " = (" + data + ")ReadInt(bytes, ref index);\r\n"; }elsereadingStr += "\t\t\t" + name + " = " + GetFieldReadingStr(type) + ";\r\n";}return readingStr;}private string GetFieldReadingStr(string type){switch (type){case "byte":return "ReadByte(bytes, ref index)";case "int":return "ReadInt(bytes, ref index)";case "short":return "ReadShort(bytes, ref index)";case "long":return "ReadLong(bytes, ref index)";case "bool":return "ReadBool(bytes, ref index)";case "float":return "ReadFloat(bytes, ref index)";case "string":return "ReadString(bytes, ref index)";default:return "ReadData<" + type + ">(bytes, ref index)";}}}

断线重连

总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/881473.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaEE之多线程进阶-面试问题

一.常见的锁策略 锁策略不是指某一个具体的锁&#xff0c;所有的锁都可以往这些锁策略中套 1.悲观锁与乐观锁 预测所冲突的概率是否高&#xff0c;悲观锁为预测锁冲突的概率较高&#xff0c;乐观锁为预测锁冲突的概率更低。 2.重量级锁和轻量级锁 从加锁的开销角度判断&am…

ssm教师办公管理系统的设计与实现+jsp

系统包含&#xff1a;源码论文 所用技术&#xff1a;SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习&#xff0c;获取源码请私聊我 需要定制请私聊 目 录 目 录 III 1 绪论 1 1.1 研究背景 1 1.2 目的和意义 1 1.3 论文结构安排 2 2 相关技术 3 2.1 JSP技…

大模型存储选型 JuiceFS 在关键环节性能详解

从去年开始&#xff0c;LLM大语言模型领域发展迅速、如 LLaMA、ChatGLM、Baichuan、Qwen 和 yi-model 等基础模型&#xff08;Foundation Models&#xff09;的数量显著增加。众多企业也开始基于这些基础模型做 post-training 的相关工作&#xff0c;以开发特定垂直领域的模型实…

一键生成二维码的源码系统 电脑+手机版自适应代码 带完整的安装代码包以及搭建部署教程

系统概述 一键生成二维码的源码系统是一款集二维码生成、管理和应用于一体的综合性平台。它采用先进的技术和算法&#xff0c;能够快速、准确地生成各种类型的二维码&#xff0c;包括文本、链接、图片等。同时&#xff0c;该系统还具备高度的灵活性和可扩展性&#xff0c;能够…

基于matlab变频器控制交流电机调速系统的设计与仿真(毕业论文)

目录 摘要 I ABSTRACT II 绪论 1 1交流调速技术发展概况 2 1.1电力电子器件 3 1.2变流技术 3 1.3变频调速的控制方式 4 1.4MATLAB/Simulink仿真介绍 4 2逆变电路的建模与仿真 5 2.1绝缘栅双极型晶体管 6 2.2三相桥式逆变电路的基本原理 6 2.3正弦脉冲宽度调制&#xff08;SPWM&…

六西格玛设计DFSS方法论在消费级无人机设计中的应用——张驰咨询

本文基于六西格玛设计方法论&#xff0c;对消费级无人机的设计流程进行系统化研究&#xff0c;探讨如何通过六西格玛设计的理念、工具和方法提升无人机产品的设计质量和市场竞争力。文章从市场定位、客户需求分析出发&#xff0c;深入到关键KPI指标的制定&#xff0c;并逐步阐述…

【数字孪生智慧园区物联网平台建设】智慧园区整体解决方案和集成方案(PPT+Word+实现)

数字孪生智慧园区物联网平台建设 1. 安防监控 2. 消防系统 3. 巡更系统 4. 红外线系统 5. 车辆识别 6. 人流管理 7. 消防机房 8. 能耗管理 9. 配电室 10. 智能集成 软件全套资料部分文档清单&#xff1a; 工作安排任务书&#xff0c;可行性分析报告&#xff0c;立项申请审批表&…

【华为HCIP实战课程十】OSPF网络DR和BDR实战讲解,网络工程师

一、DR与BDR的基础介绍 点到点同步LSA成本小 多点接入网络同步LSA成本大,需要DR/BDR 由于MA网络中,任意两台路由器都需要传递路由信息,网络中有n台路由器,则需要建立n*(n-1)/2个邻接关系。任何一台路由器的路由变化都会导致多次传递,浪费了带宽资源,DR和BDR应运而生!…

uibot发送邮件:自动化邮件发送教程详解!

uibot发送邮件的操作指南&#xff1f;uibot发送邮件的两种方式&#xff1f; 在现代办公环境中&#xff0c;自动化流程的引入极大地提高了工作效率。uibot发送邮件功能成为了许多企业和个人实现邮件自动化发送的首选工具。AokSend将详细介绍如何使用uibot发送邮件。 uibot发送…

使用Pytorch写简单线性回归

文章目录 Pytorch一、Pytorch 介绍二、概念三、应用于简单线性回归 1.代码框架2.引用3.继续模型(1)要定义一个模型&#xff0c;需要继承nn.Module&#xff1a;(2)如果函数的参数不具体指定&#xff0c;那么就需要在__init__函数中添加未指定的变量&#xff1a; 2.定义数据3.实例…

IP地址类型选择指南:动态IP、静态IP还是数据中心IP?

你是否曾经困惑于如何选择最适合业务需求的IP地址类型&#xff1f;面对动态IP、静态IP和数据中心IP这三种选择&#xff0c;你是否了解它们各自对你的跨境在线业务可能产生的深远影响&#xff1f; 在跨境电商领域&#xff0c;选择合适的IP类型对于业务的成功至关重要。动态IP、…

gitee开源商城diygw-mall

DIYGW可视化开源商城系统。所的界面布局显示都通过低代码可视化开发工具生成源码实现。支持集成微信小程序支付。 DIYGW可视化开源商城系统是一款基于thinkphp8 framework、 element plus admin、uniapp开发而成的前后端分离系统。 开源商城项目源码地址&#xff1a;diygw商城…

Java中String类的常见操作Api

目录 String类的常见操作 1).int indexOf (char 字符) 2).int lastIndexOf(char 字符) 3).int indexOf(String 字符串) 4).int lastIndexOf(String 字符串) 5).char charAt(int 索引) 6).Boolean endWith(String 字符串) 7).int length() 8).boolean equals(T 比较对象) 9).b…

区块链积分系统:重塑支付安全与商业创新的未来

在当今社会&#xff0c;数字化浪潮席卷全球&#xff0c;支付安全与风险管理议题日益凸显。随着交易频次与规模的不断扩大&#xff0c;传统支付体系正面临前所未有的效率、合规性和安全挑战。 区块链技术&#xff0c;凭借其去中心化、高透明度以及数据不可篡改的特性&#xff0c…

SSH 公钥认证:从gitlab clone项目repo到本地

这篇文章的分割线以下文字内容由 ChatGPT 生成&#xff08;我稍微做了一些文字上的调整和截图的补充&#xff09;&#xff0c;我review并实践后觉得内容没有什么问题&#xff0c;由此和大家分享。 假如你想通过 git clone git10.12.5.19:your_project.git 命令将 git 服务器上…

简单的maven nexus私服学习

简单的maven nexus私服学习 1.需求 我们现在使用的maven私服是之前同事搭建的&#xff0c;是在公司的一台windows电脑上面&#xff0c;如果出问题会比较难搞&#xff0c;所以现在想将私服迁移到我们公司的测试服务器上&#xff0c;此处简单了解一下私服的一些配置记录一下&am…

多线程(二):Thread类常见的属性和方法

目录 1、run & start 2、Thread类常见的属性和方法 2.1 构造方法 2.2 属性 3、后台进程 & 前台进程 4、setDaemon 5、isAlive 6、终止一个线程 6.1 变量捕获 6.2 currentThread & isInterrupted & interrupt 1、run & start 在多线程&#xff08…

Java面试宝典-Java集合01

Java面试宝典-Java集合01 目录 Java面试宝典-Java集合01 1、Java中常用的集合有哪些&#xff1f; 2、Collection 和 Collections 有什么区别&#xff1f; 3、为什么集合类没有实现 Cloneable 和 Serializable 接口&#xff1f; 4、数组和集合有什么本质区别&#xff1f; 5、数组…

Java | Leetcode Java题解之第470题用Rand7()实现Rand10()

题目&#xff1a; 题解&#xff1a; class Solution extends SolBase {public int rand10() {int a, b, idx;while (true) {a rand7();b rand7();idx b (a - 1) * 7;if (idx < 40) {return 1 (idx - 1) % 10;}a idx - 40;b rand7();// get uniform dist from 1 - 63…

蓝桥杯【物联网】零基础到国奖之路:十七. 扩展模块之单路ADC和NE555

蓝桥杯【物联网】零基础到国奖之路:十七. 扩展模块之单路ADC和NE555 第一节 硬件解读第二节 CubeMx配置第三节 代码1&#xff0c;脉冲部分代码2&#xff0c;ADC部分代码![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/57531a4ee76d46daa227ae0a52993191.png) 第一节 …