《Unity3D网络游戏实战》第7章
《Unity3D网络游戏实战》第7章
- 服务端架构
- 总体架构
- 模块划分
- 游戏流程
- Json编码解码
- 添加协议文件
- 引用System.web.Extensions
- 修改MsgBase类
- 测试
- 网络模块
- 整体结构
- ClientState
- 开启监听和多路复用
- 处理监听消息
- 处理客户端消息
- 关闭连接
- 处理协议
- Timer
- 发送协议
- 测试
- 心跳机制
- lastPingTime
- 时间戳
- 回应MsgPing协议
- 超时处理
- 测试程序
- 玩家的数据结构
- 完整的ClientState
- PlayerData
- Player
- PlayerManager
- 配置MySQL数据库
- 安装和启动MySQL数据库
- 安装Navicat for MySQL
- 配置数据库
- 安装connector
- MySQL基础知识
- 数据库模块
- 连接数据库
- 防止SQL注入
- IsAccountExist
- Register
- CreatePlayer
- CheckPassword
- GetPlayerData
- UpdatePlayerData
- 登录注册功能
- 注册登录协议
- 记事本协议
- 注册功能
- 登录功能
- 退出功能
- 获取文本功能
- 保存文本功能
- 完整代码
服务端架构
总体架构
单进程服务端结构。
- 处理客户端的消息
客户端与服务端通过TCP连接并传递数据。 - 存储玩家数据
MySQL数据库保存玩家数据。
模块划分
- 网络底层
处理网络连接的底层模块,有粘包半包、协议解析等功能。
- 消息处理
游戏逻辑层,比如收到MsgMove协议,服务端会记录玩家坐标,然后广播。 - 事件处理
玩家上线和下线等。上线,初始化;下线,数据记录。
- 数据库底层
提供保存玩家数据、读取玩家数据、注册、检验用户名密码等功能,封装服务端和数据库的交互。
- 存储结构
指定保存数据,比如金币、等级、经验、文本。
游戏流程
- 连接阶段
客户端调用Connect连接服务端。连通后,客户端发送登录协议(含用户名、密码等信息),检验通过后,服务端从数据库获取该角色数据,登录成功。 - 交互阶段
双端互通协议,MsgMove、MsgAttack等。 - 登出阶段
玩家下线,服务端保存数据。定时保存玩家数据(每隔几分钟),相对安全,能够挽回部分突然挂掉在线玩家数据,频繁写数据库,性能较差;玩家下线时保存数据。
状态 | 说明 |
---|---|
连接但未登录 | Connect连接,角色未关联,需输入账号密码,服务端验证后从数据库读取角色数据并关联 |
登录成功 | 连接和角色关联后,玩家可操作游戏角色,如移动、攻击等 |
Json编码解码
类的序列化。
- 服务端与客户端交互需要编码和解码Json协议。
- PlayerData(存储玩家数据,金币、等级等)类对象需要需要序列化为Json字符串存入数据库。
添加协议文件
net网络模块,proto协议文件。
引用System.web.Extensions
修改MsgBase类
using System;
using System.Linq;
using System.Web.Script.Serialization;public class MsgBase {public string protoName = "null";//编码器static JavaScriptSerializer Js = new JavaScriptSerializer();//编码public static byte[] Encode(MsgBase msgBase){string s = Js.Serialize(msgBase); return System.Text.Encoding.UTF8.GetBytes(s);}//解码public static MsgBase Decode(string protoName, byte[] bytes, int offset, int count){string s = System.Text.Encoding.UTF8.GetString(bytes, offset, count);MsgBase msgBase = (MsgBase)Js.Deserialize(s, Type.GetType(protoName));return msgBase;}//编码协议名(2字节长度+字符串)public static byte[] EncodeName(MsgBase msgBase){//名字bytes和长度byte[] nameBytes = System.Text.Encoding.UTF8.GetBytes(msgBase.protoName);Int16 len = (Int16)nameBytes.Length;//申请bytes数值byte[] bytes = new byte[2+len];//组装2字节的长度信息bytes[0] = (byte)(len%256);bytes[1] = (byte)(len/256);//组装名字bytesArray.Copy(nameBytes, 0, bytes, 2, len);return bytes;}//解码协议名(2字节长度+字符串)public static string DecodeName(byte[] bytes, int offset, out int count){count = 0;//必须大于2字节if(offset + 2 > bytes.Length){return "";}//读取长度Int16 len = (Int16)((bytes[offset+1] << 8 )| bytes[offset] );//长度必须足够if(offset + 2 + len > bytes.Length){return "";}//解析count = 2+len;string name = System.Text.Encoding.UTF8.GetString(bytes, offset+2, len);return name;}
}
测试
using System;class Test {public static void Main(string[] args) {MsgMove msgMove = new MsgMove();msgMove.x = 100;msgMove.y = -20;byte[] bytes = MsgBase.Encode(msgMove);string s = System.Text.Encoding.UTF8.GetString(bytes);Console.WriteLine(s);s = "{\"protoName\":\"MsgMove\",\"x\":100,\"y\":-20,\"z\":0}";bytes = System.Text.Encoding.UTF8.GetBytes(s);msgMove = (MsgMove) MsgBase.Decode("MsgMove", bytes, 0, bytes.length);Console.WriteLine(msgMove.x);Console.WriteLine(msgMove.y);Console.WriteLine(msgMove.z);}
}
网络模块
整体结构
- 网络管理器NetManager,处理select多路复用。
- ClientState类,定义客户端信息。
- MsgHandler类,处理网络消息,根据消息类型,分拆到多个文件中(BattleMsgHandler.cs处理战斗相关协议,SysMsgHandler处理MsgPing,MsgPong等系统协议)。
- 事件处理类EventHandler。
程序引入玩家列表,玩家登录后clientState与player对象关联。通过clientState是否持有player对象判断客户端状态。
logic,代表游戏逻辑部分。
ClientState
客户端信息,一个客户端连接对应一个ClientState对象。
using System.Net.Sockets;public class ClientState
{public Socket socket; public ByteArray readBuff = new ByteArray(); //Pingpublic long lastPingTime = 0;//玩家public Player player;
}
开启监听和多路复用
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;class NetManager {//监听Socketpublic static Socket listenfd;//客户端Socket及状态信息public static Dictionary<Socket, ClientState> clients = new Dictionary<Socket, ClientState>();//Select的检查列表static List<Socket> checkRead = new List<Socket>();//ping间隔public static long pingInterval = 30;
}
public static void StartLoop(int listenPort) {//Socketlistenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//BindIPAddress ipAdr = IPAddress.Parse("0.0.0.0");IPEndPoint ipEp = new IPEndPoint(ipAdr, listenPort);listenfd.Bind(ipEp);//Listenlistenfd.Listen(0);Console.WriteLine("[服务器]启动成功");//循环while(true){ResetCheckRead(); //重置checkReadSocket.Select(checkRead, null, null, 1000);//阻塞1秒,直到可读//检查可读对象for(int i = checkRead.Count-1; i>=0; i--){Socket s = checkRead[i];if(s == listenfd){ReadListenfd(s);}else{ReadClientfd(s);}}//超时Timer();}
}
//填充checkRead列表
public static void ResetCheckRead(){checkRead.Clear();checkRead.Add(listenfd); foreach(ClientState s in clients.Values){checkRead.Add(s.socket);}
}
处理监听消息
//读取Listenfd
public static void ReadListenfd(Socket listenfd){try{Socket clientfd = listenfd.Accept();//访问套接字时出错、Socket已经关闭等情形下会抛出异常Console.WriteLine("[Accept]" + clientfd.RemoteEndPoint.ToString());ClientState state = new ClientState();state.socket = clientfd;state.lastPingTime = GetTimeStamp();clients.Add(clientfd, state);}catch(SocketException ex){Console.WriteLine("[Accept fail]" + ex.ToString());}
}
处理客户端消息
//读取Clientfd
public static void ReadClientfd(Socket clientfd){ClientState state = clients[clientfd];ByteArray readBuff = state.readBuff;//接收int count = 0;//缓冲区不够,清除,若依旧不够,只能返回//缓冲区长度只有1024,单条协议超过缓冲区长度时会发生错误,根据需要调整长度if(readBuff.remain <=0){OnReceiveData(state);readBuff.MoveBytes();};if(readBuff.remain <=0){Console.WriteLine("Receive fail , maybe msg length > buff capacity");Close(state);return;}try{count = clientfd.Receive(readBuff.bytes, readBuff.writeIdx, readBuff.remain, 0);}catch(SocketException ex){//发生异常,连接失效,Close。Console.WriteLine("Receive SocketException " + ex.ToString());Close(state);return;}//客户端关闭if(count <= 0){//客户端主动断开连接,服务端收到长度为0数据,Close。Console.WriteLine("Socket Close " + clientfd.RemoteEndPoint.ToString());Close(state);return;}//消息处理readBuff.writeIdx += count;//处理二进制消息OnReceiveData(state);//处理粘包分包问题//移动缓冲区readBuff.CheckAndMoveBytes();
}
关闭连接
- 分发OnDisconnect事件,让程序可以在玩家掉线时做些处理;
- 调用socket.Close关闭连接;
- 将客户端状态state移除clients列表。
//关闭连接
public static void Close(ClientState state){//消息分发MethodInfo mei = typeof(EventHandler).GetMethod("OnDisconnect");object[] ob = {state};mei.Invoke(null, ob);//关闭state.socket.Close();clients.Remove(state.socket);
}
处理协议
//数据处理
public static void OnReceiveData(ClientState state){ByteArray readBuff = state.readBuff;//消息长度if(readBuff.length <= 2) {return;}Int16 bodyLength = readBuff.ReadInt16();//消息体if(readBuff.length < bodyLength){return;}//解析协议名int nameCount = 0;string protoName = MsgBase.DecodeName(readBuff.bytes, readBuff.readIdx, out nameCount);if(protoName == ""){Console.WriteLine("OnReceiveData MsgBase.DecodeName fail");Close(state);return;}readBuff.readIdx += nameCount;//解析协议体int bodyCount = bodyLength - nameCount;MsgBase msgBase = MsgBase.Decode(protoName, readBuff.bytes, readBuff.readIdx, bodyCount);readBuff.readIdx += bodyCount;readBuff.CheckAndMoveBytes();//分发消息MethodInfo mi = typeof(MsgHandler).GetMethod(protoName);object[] o = {state, msgBase};Console.WriteLine("[Receive]" + protoName);if(mi != null){mi.Invoke(null, o);}else{Console.WriteLine("OnReceiveData Invoke fail " + protoName);}//继续读取消息if(readBuff.length > 2){OnReceiveData(state);}
}
Timer
//定时器
static void Timer(){//消息分发MethodInfo mei = typeof(EventHandler).GetMethod("OnTimer");object[] ob = {};mei.Invoke(null, ob);
}
发送协议
//发送
public static void Send(ClientState cs, MsgBase msg){//状态判断if(cs == null){return;}if(!cs.socket.Connected){return;}//数据编码byte[] nameBytes = MsgBase.EncodeName(msg);byte[] bodyBytes = MsgBase.Encode(msg);int len = nameBytes.Length + bodyBytes.Length;byte[] sendBytes = new byte[2+len];//组装长度sendBytes[0] = (byte)(len%256);sendBytes[1] = (byte)(len/256);//组装名字Array.Copy(nameBytes, 0, sendBytes, 2, nameBytes.Length);//组装消息体Array.Copy(bodyBytes, 0, sendBytes, 2+nameBytes.Length, bodyBytes.Length);//为简化代码,不设置回调try{cs.socket.BeginSend(sendBytes,0, sendBytes.Length, 0, null, null);}catch(SocketException ex){Console.WriteLine("Socket Close on BeginSend" + ex.ToString()); }
}
测试
- 协议处理
BattleMsgHandler.cs
using System;public partial class MsgHandler {public static void MsgMove(ClientState c, MsgBase msgBase){MsgMove msgMove = (MsgMove)msgBase;Console.WriteLine(msgMove.x);msgMove.x++;NetManager.Send(c, msgMove);}
}
SysMsgHandler.cs
using System;public partial class MsgHandler {public static void MsgPing(ClientState c, MsgBase msgBase){Console.WriteLine("MsgPing");c.lastPingTime = NetManager.GetTimeStamp();MsgPong msgPong = new MsgPong();NetManager.Send(c, msgPong);}
}
partial表明类是局部类型,允许将一个类、结构或接口分成几个部分,分别实现在几个不同的cs文件中。
- 事件处理
using System;public partial class EventHandler {public static void OnDisconnect(ClientState c){Console.WriteLine("Close");}public static void OnTimer(){}
}
- 启动网络监听
using System;class Server {public static void Main(strin[] args) {NetManager.StartLoop(8888);}
}
- 开始测试
客户端发送MsgMove协议。
心跳机制
lastPingTime
using System.Net.Sockets;public class ClientState
{public Socket socket; public ByteArray readBuff = new ByteArray(); //Pingpublic long lastPingTime = 0;//玩家public Player player;
}
class NetManager {public static long pingInterval = 30;
}
时间戳
1970年1月1日零点到现在的秒数。
//获取时间戳
public static long GetTimeStamp() {TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);return Convert.ToInt64(ts.TotalSeconds);
}
回应MsgPing协议
using System;public partial class MsgHandler {public static void MsgPing(ClientState c, MsgBase msgBase){Console.WriteLine("MsgPing");c.lastPingTime = NetManager.GetTimeStamp();MsgPong msgPong = new MsgPong();NetManager.Send(c, msgPong);}
}
超时处理
服务端长时间未收到MsgPing时,认为连接已经断开。
public static void OnTimer(){CheckPing();
}//Ping检查
public static void CheckPing(){//现在的时间戳long timeNow = NetManager.GetTimeStamp();//遍历,删除foreach(ClientState s in NetManager.clients.Values){if(timeNow - s.lastPingTime > NetManager.pingInterval*4){Console.WriteLine("Ping Close " + s.socket.RemoteEndPoint.ToString());NetManager.Close(s);return;}}
}
测试程序
设置服务端pingInterval值为2。
玩家的数据结构
完整的ClientState
using System.Net.Sockets;public class ClientState {public Socket socket; public ByteArray readBuff = new ByteArray(); //Pingpublic long lastPingTime = 0;//玩家public Player player;
}
PlayerData
public class PlayerData{//金币public int coin = 0;//记事本public string text = "new text";
}
Player
using System;public class Player {//idpublic string id = "";//指向ClientStatepublic ClientState state;//构造函数public Player(ClientState state){this.state = state;}//临时数据,如:坐标public int x; public int y; public int z;//数据库数据public PlayerData data;//发送信息public void Send(MsgBase msgBase){NetManager.Send(state, msgBase);}
}
PlayerManager
using System;
using System.Collections.Generic;public class PlayerManager {//玩家列表static Dictionary<string, Player> players = new Dictionary<string, Player>();//玩家是否在线public static bool IsOnline(string id){return players.ContainsKey(id);}//获取玩家public static Player GetPlayer(string id){return players[id];}//添加玩家public static void AddPlayer(string id, Player player){players.Add(id, player);}//删除玩家public static void RemovePlayer(string id){players.Remove(id);}
}
配置MySQL数据库
- 安装和启动MySQL服务器,让它监听某个端口;
- 使用库编码和解码MySQL特定形式的协议。
安装和启动MySQL数据库
xampp安装包安装,xmapp-control.exe启动,Start按钮开启MySQL服务。默认数据库端口3306,用户root,密码空。
安装Navicat for MySQL
专为MySQL数据库服务的管理工具。
新建连接,连接名:127.0.0.1;
主机名或IP地址:127.0.0.1;
端口:3306;
用户名:root;
密码:
配置数据库
新建game库,包含account和player表。
account含id(账号,text)和pw(密码,text)。
player含id和data(数据,text)。
安装connector
引用MySql.Data.dll
MySQL基础知识
MySQL数据类型 | 子类 |
---|---|
数字类型 | 整数:tinyint、smallint、mediumint、int、bigint 浮点数:float、double、real、decimal |
日期和时间 | date、time、datetime、timestamp、year |
字符串 | char、varchar |
文本 | tinytext、text、mediumtext、longtext |
二进制 | tinyblob、blob、mediumblob、longblob |
MySQL语句 | 说明 |
---|---|
select | 查询数据 select 列名称 from 表名称 [查询条件]; select * from msg where name = “小明”; |
insert | 插入数据 insert [into] 表名 [(列名1,列名2,列名3,…)] values(值1,值2,值3,…); insert into msg values(1, “小明”, “你好”); insert into students(“name”, “msg”) values(“小红”, “Love”); |
update | 更新数据 update 表名称 set 列名称 = 新值 where 更新条件; update msg set msg = “ha” where id = 123; |
delete | 删除数据 delete from 表名称 where 删除条件; delete from msg where id = 123; |
操作MySQL流程:
- 连接MySQL(数据库地址、端口、用户名、密码)
- 选择数据库
- 执行SQL语句
- 关闭数据库
数据库模块
连接数据库
DbManager.cs
using System;
using MySql.Data.MySqlClient;
using System.Text.RegularExpressions;
using System.Web.Script.Serialization;public class DbManager {public static MySqlConnection mysql;static JavaScriptSerializer Js = new JavaScriptSerializer();//连接mysql数据库public static bool Connect(string db, string ip, int port, string user, string pw) {//创建MySqlConnection对象mysql = new MySqlConnection();//连接参数string s = string.Format("Database={0};Data Source={1}; port={2};User Id={3}; Password={4}", db, ip, port, user, pw);mysql.ConnectionString = s;//连接try{mysql.Open();Console.WriteLine("[数据库]connect succ ");return true;}catch (Exception e){Console.WriteLine("[数据库]connect fail, " + e.Message);return false;}}
}
using System;class Test {public static void Main(string[] args) {DbManager.Connect("game", "127.0.0.1", 3306, "root", "");}
}
csc DbManager.cs Test.cs -reference:MySql.Data.dll
防止SQL注入
SQL注入,指通过输入请求,把SQL命令插入到SQL语句中,以达到欺骗服务器执行恶意SQL命令的目的。
string sql = "select * from player where id = " + id;
若
id = "xiaoming; delete * from player;";
则
sql = "select * from player where id = xiaoming; delete * from player;";
在拼装SQL语句前,对用户输入的字符串进行安全性检测(含有逗号、分号等特殊字符的字符串判定为不安全字符串),能够有效地防止SQL注入。
using System.Text.RegularExpressions;//判定安全字符串
private static bool IsSafeString(string str) {return !Regex.IsMatch(str, @"[-|;|,|\/|\(|\)|\[|\]|\}|\{|%|@|\*|!|\']");
}
IsAccountExist
//是否存在该用户
public static bool IsAccountExist(string id) {//防sql注入if (!DbManager.IsSafeString(id)){return false;}//sql语句string s = string.Format("select * from account where id='{0}';", id); //查询try {MySqlCommand cmd = new MySqlCommand(s, mysql); MySqlDataReader dataReader = cmd.ExecuteReader(); bool hasRows = dataReader.HasRows;dataReader.Close();return !hasRows;}catch(Exception e){Console.WriteLine("[数据库] IsSafeString err, " + e.Message);return false;}
}
Register
//注册
public static bool Register(string id, string pw) {//防sql注入if(!DbManager.IsSafeString(id)){Console.WriteLine("[数据库] Register fail, id not safe");return false;}if(!DbManager.IsSafeString(pw)){Console.WriteLine("[数据库] Register fail, pw not safe");return false;}//能否注册if(!IsAccountExist(id)) {Console.WriteLine("[数据库] Register fail, id exist");return false;}//写入数据库User表string sql = string.Format("insert into account set id ='{0}' ,pw ='{1}';", id, pw);try{MySqlCommand cmd = new MySqlCommand(sql, mysql);cmd.ExecuteNonQuery();return true;}catch(Exception e) {Console.WriteLine("[数据库] Register fail " + e.Message);return false;}
}
明文密码应该加密(md5加密等)存入数据库。
测试
using System;class Test {public static void Main(string[] args) {if(!DbManager.Connect("game", "127.0.0.1", 3306, "root", "")) {return;}//测试if(DbManager.Register("lpy", "123456")){Console.WriteLine("注册成功");}}
}
CreatePlayer
//创建角色
public static bool CreatePlayer(string id){//防sql注入if(!DbManager.IsSafeString(id)){Console.WriteLine("[数据库] CreatePlayer fail, id not safe");return false;}//序列化PlayerData playerData = new PlayerData();string data = Js.Serialize(playerData); //写入数据库string sql = string.Format("insert into player set id ='{0}' ,data ='{1}';", id, data);try {MySqlCommand cmd = new MySqlCommand(sql, mysql);cmd.ExecuteNonQuery();return true;} catch(Exception e){Console.WriteLine("[数据库] CreatePlayer err, " + e.Message);return false;}
}
测试
using System;class Test {public static void Main(string[] args) {if(!DbManager.Connect("game", "127.0.0.1", 3306, "root", "")) {return;}//注册if(DbManager.Register("lpy", "123456")){Console.WriteLine("注册成功");}//测试if(DbManager.CreatePlayer("aglab")){Console.WriteLine("创建成功");}}
}
CheckPassword
//检测用户名密码
public static bool CheckPassword(string id, string pw) {//防sql注入if(!DbManager.IsSafeString(id)){Console.WriteLine("[数据库] CheckPassword fail, id not safe");return false;}if(!DbManager.IsSafeString(pw)){Console.WriteLine("[数据库] CheckPassword fail, pw not safe");return false;}//查询string sql = string.Format("select * from account where id='{0}' and pw='{1}';", id, pw); try {MySqlCommand cmd = new MySqlCommand(sql, mysql); MySqlDataReader dataReader = cmd.ExecuteReader();bool hasRows = dataReader.HasRows;dataReader.Close();return hasRows;}catch(Exception e){Console.WriteLine("[数据库] CheckPassword err, " + e.Message);return false;}
}
GetPlayerData
//获取玩家数据
public static PlayerData GetPlayerData(string id){//防sql注入if(!DbManager.IsSafeString(id)){Console.WriteLine("[数据库] GetPlayerData fail, id not safe");return null;}//sqlstring sql = string.Format("select * from player where id ='{0}';", id);try{//查询MySqlCommand cmd = new MySqlCommand(sql, mysql); MySqlDataReader dataReader = cmd.ExecuteReader(); if(!dataReader.HasRows){dataReader.Close();return null;}//读取dataReader.Read();string data = dataReader.GetString("data");//反序列化PlayerData playerData = Js.Deserialize<PlayerData>(data);dataReader.Close();return playerData;}catch(Exception e){Console.WriteLine("[数据库] GetPlayerData fail, " + e.Message);return null;}
}
UpdatePlayerData
//保存角色
public static bool UpdatePlayerData(string id, PlayerData playerData){//序列化string data = Js.Serialize(playerData); //sqlstring sql = string.Format("update player set data='{0}' where id ='{1}';", data, id);//更新try {MySqlCommand cmd = new MySqlCommand(sql, mysql);cmd.ExecuteNonQuery();return true;} catch(Exception e){Console.WriteLine("[数据库] UpdatePlayerData err, " + e.Message);return false;}
}
测试
DbManager.CreatePlayer("aglab");
PlayerData pd = DbManager.GetPlayerData("aglab");
pd.coin = 256;
DbManager.UpdatePlayerData("aglab", pd);
登录注册功能
在线记事本
- 连接
- 注册(MsgRegister协议)
- 登录(MsgLogin协议)
- 获取文本(MsgGetText协议获取已保存的文本信息)
- 操作(编辑文本)
- 保存文本(MsgSaveText协议更新文本信息)
- 退出
注册登录协议
LoginMsg.cs
//注册
public class MsgRegister:MsgBase {public MsgRegister() {protoName = "MsgRegister";}//客户端发public string id = "";public string pw = "";//服务端回(0-成功,1-失败)public int result = 0;
}//登陆
public class MsgLogin:MsgBase {public MsgLogin() {protoName = "MsgLogin";}//客户端发public string id = "";public string pw = "";//服务端回(0-成功,1-失败)public int result = 0;
}//踢下线(服务端推送)
public class MsgKick:MsgBase {public MsgKick() {protoName = "MsgKick";}//原因(0-其他人登陆同一账号)public int reason = 0;
}
记事本协议
NotepadMsg.cs
//获取记事本内容
public class MsgGetText:MsgBase {public MsgGetText() {protoName = "MsgGetText";}//服务端回public string text = "";
}//保存记事本内容
public class MsgSaveText:MsgBase {public MsgSaveText() {protoName = "MsgSaveText";}//客户端发public string text = "";//服务端回(0-成功 1-文字太长)public int result = 0;
}
注册功能
//注册协议处理
public static void MsgRegister(ClientState c, MsgBase msgBase){MsgRegister msg = (MsgRegister)msgBase;//注册if(DbManager.Register(msg.id, msg.pw)){DbManager.CreatePlayer(msg.id);msg.result = 0;}else{msg.result = 1;}NetManager.Send(c, msg);
}
登录功能
//登陆协议处理
public static void MsgLogin(ClientState c, MsgBase msgBase){MsgLogin msg = (MsgLogin)msgBase;//密码校验if(!DbManager.CheckPassword(msg.id, msg.pw)){msg.result = 1;NetManager.Send(c, msg);return;}//不允许再次登陆if(c.player != null){msg.result = 1;NetManager.Send(c, msg);return;}//如果已经登陆,踢下线if(PlayerManager.IsOnline(msg.id)){//发送踢下线协议Player other = PlayerManager.GetPlayer(msg.id);MsgKick msgKick = new MsgKick();msgKick.reason = 0;other.Send(msgKick);//断开连接NetManager.Close(other.state);}//获取玩家数据PlayerData playerData = DbManager.GetPlayerData(msg.id);if(playerData == null){msg.result = 1;NetManager.Send(c, msg);return;}//构建PlayerPlayer player = new Player(c);player.id = msg.id;player.data = playerData;PlayerManager.AddPlayer(msg.id, player);c.player = player;//返回协议msg.result = 0;player.Send(msg);
}
退出功能
public static void OnDisconnect(ClientState c){Console.WriteLine("Close");//Player下线if(c.player != null){//保存数据DbManager.UpdatePlayerData(c.player.id, c.player.data);//移除PlayerManager.RemovePlayer(c.player.id);}
}
获取文本功能
//获取记事本内容
public static void MsgGetText(ClientState c, MsgBase msgBase){MsgGetText msg = (MsgGetText)msgBase;Player player = c.player;if(player == null) return;//获取textmsg.text = player.data.text;player.Send(msg);
}
保存文本功能
//保存记事本内容
public static void MsgSaveText(ClientState c, MsgBase msgBase){MsgSaveText msg = (MsgSaveText)msgBase;Player player = c.player;if(player == null) return;//获取textplayer.data.text = msg.text;player.Send(msg);
}
完整代码
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- 网页前端第三次培训笔记(CSS选择器的使用)
1,如何使用CSS CSS 可以通过以下方式添加到HTML中: 内联样式- 在HTML元素中使用"style" 属性内部样式表 -在HTML文档头部 <head> 区域使用<style> 元素 来包含CSS外部引用 - 使用外部 CSS 文件 最好的方式是通过外部引用CSS文件. 1&#x…...
2024/5/4 15:55:03 - 安卓Android源码,安卓项目,安卓系统
安卓Android源码,安卓项目,安卓系统 安卓鞋类APP源码 Android Studio开发基于安卓Android的鞋类APP源码 包含完整Word报告,演示视频,PPT,手机运行软件,电脑运行程序编号:9219650909746437无人区玫瑰...
2024/4/13 13:57:00 - CentOs6.10 安装后无网卡问题解决方案
CentOs6.10 安装后无网络问题解决方案 【问题描述】 CentOs6.10 系统新安装后发现连不上互联网 【排查步骤】 查看网络配置 执行命令ifconfig,发现只有lo,没有网卡 [rootlocalhost ~]# ifconfig lo Link encap:Local Loopback inet addr:1…...
2024/4/13 13:57:00 - Object类
Object类是java中所有类的超类或者叫基类 就是祖宗 构造方法: Object() 方法: equals();判断两个对象是否相等 1.1Object类下面的equals方法 public boolean equals(Object obj) {return (this obj);} Object类下面使用的,就意味着Obj…...
2024/4/13 13:57:00 - 【UEFI基础】EDK编译生成的二进制的结构
转载UEFI编译生成文件二进制描述 ———————————————— 版权声明:本文为CSDN博主「jiangwei0512」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/jiangwei0…...
2024/4/13 13:56:45 - 云计算基础服务文件(六)存储NFS_SMB
NFS介绍 Network File System(NFS) fastdfs 多机共享数据 数据的备份 (常用于Linux与Linux之间) 前提: 防火墙 Selinux关闭状态 存储端: node02: /imgdata 客户端: node01: /data/web/img 所有节点: yum install nfs-utils rpcbind -y 存储端: node02 nfs除了主程序…...
2024/5/4 17:36:16 - 技术债务研究综述X4
目录 Paper1: Managing Technical Debt 与金融债务的比较 管理你的债务 不同角度的债务成本 总结 Paper2: Technical Debt: From Metaphor to Theory and Practice 组织技术债务状况 处理技术债务 统一理论? 在这个问题上 Paper3: 10 Years of Technical …...
2024/4/13 13:56:50 - 低压400瓦同步电机驱动器方案低压400瓦驱动器方案
低压400瓦同步电机驱动器方案低压400瓦驱动器方案,带霍尔传感器,恒转速,pi调节,带485通信。资料包括图纸程序 编号:1250650855484703asdf2013_2229...
2024/4/5 2:49:27 - 牛客真题编程——day14
编程环境:c 1、字符串价值 描述:有一种有趣的字符串价值计算方式:统计字符串中每种字符出现的次数,然后求所有字符次数的平方和作为字符串的价值 例如: 字符串"abacaba",里面包括4个a,2个b,1个c,于是这个字符串的价值为4 * 4 2 * 2 1 * 1 …...
2024/4/15 5:49:47 - 基于Python的人脸识别 附带说明文档
项目:基于Python的人脸识别 环境:Windows系统、pycharm 技术:opencv、PyQt5 库文件:numpy、opencv-contrib-python、 opencv-python、pillow、PyQt5 功能:先要采集人脸数据,丰富人脸基本的数 据库&…...
2024/4/21 1:37:55 - STM32_1
一.呼吸灯基本步骤 1.设置引脚 直接点击设置引脚为output 按鼠标中键移动位置 2.设置SYS 串口总线 3.设置时钟 全部选择晶振 选择可以按照路径来,32即可(x4) 4.文件设置 5.打开生成的文件 6.修改代码 魔术棒,勾选这个即可…...
2024/5/4 22:22:40 - STC单片机modbus rtu 源码,一主两从通迅
STC单片机modbus rtu 源码,一主两从通迅。触摸屏用的是显控的,也可以用其它带modbus的屏 编号:1610650822799026零度J尾酒...
2024/4/18 7:45:58 - 69. Leetcode 700. 二叉搜索树中的搜索 (二叉搜索树-基本操作类)
给定二叉搜索树(BST)的根节点 root 和一个整数值 val。你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。示例 1:输入:root [4,2,7,1,3], val 2 输出:[2,1,3] Ex…...
2024/4/16 21:17:24 - 前端学习JS第六天(P84--P89)
1、字符串的相关方法 在底层字符串是以字符数组的形式保存的,操作字符串就可以想象成数组 ①length获取字符串的长度 ②charAt()返回指定位置的字符,charCodeAt()返回指定位置的编码字符,fro…...
2024/5/4 5:26:43 - C语言项目实战学生管理系统(2)
文章目录前言一、尾添加总结前言 本篇文章我们接着上一篇文章讲解。 C语言项目实战学生管理系统(1) 一、尾添加 上篇文章我们讲到尾添加一个学生信息,这篇文章我们详细讲述如何尾添加。 //添加一个学生信息 void AddstuMSG(char arrStunum[10], char arrStunam…...
2024/4/15 5:49:47 - 【每日一题见微知著】第 279 场周赛题——周赛还是有意思啊
⭐️寒假新坑——代码之狐的每日做题笔记 ⭐️解题思路 按下标奇偶分组保存,分别排序处理获取每一位数字,排序,根据正负分类处理(负数要求重排后的正数最大,正数要求最小且没有前导零)难点是考虑优化反转操…...
2024/4/16 21:37:02 - MacOS 安装 gstreamer 最新版本(1.20.0)
近期 gstreamer 退出了最新版本 1.20.0,这个版本支持 MacOS,于是尝试安装。步骤虽然简单,但是仍然有一些需要注意的地方,在这里做一些安装步骤的说明。 下载地址:Download GStreamer 1. 安装步骤: 1.1. …...
2024/4/25 23:45:38 - 学CSS选择器,看这篇文章就够了(近2万字详解)
好久不见,甚是想念! 大家好! 我是微风洋洋 今天这篇文章就是来和大家详细聊聊CSS选择器,希望大家读完有所收获,那我辛苦码字也就值了。如果你觉得对你有一丢丢启发的话,不妨 点赞、收藏、关注支持一下&am…...
2024/4/13 13:57:55 - 安鸾靶场 宽字符注入02 靶场练习 详细过程及解决问题笔记
题目 网站URL ECSHOP演示站 - Powered by ECShop 目录 笔记 过程 进入sql注入页面 问题 判断闭合符 sql注入下的模糊查询 right 语法爆字段值 笔记 对现在我来说难度其实不大,但题目考察的一些细节要求比较高。 首先把我遇到的问题 一 一 列出。(在…...
2024/4/13 19:52:54 - 十进制整数转换n进制
#include<stdio.h> #include<string.h> /* (1)除n取余法:算法 (2)m unsigned long long n进制数 用字符数组表示 (数据结构) (m/n)(m%n) */ int i0; int main() { v…...
2024/4/13 13:57:35
最新文章
- 在剪映专业版中新增字体的方法
我一开始以为剪映专业版没有繁体字,结果发现有一个现代繁体,如图所示: 但是我已经下载了字体了,不用就可惜了。 点击汉仪粗黑繁,安装。 安装之后,重启电脑,打开剪映,就可以搜索到这个字体了。 这…...
2024/5/4 22:27:58 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/3/20 10:50:27 - 【干货】零售商的商品规划策略
商品规划,无疑是零售业的生命之源,是推动业务腾飞的强大引擎。一个精心策划的商品规划策略,不仅能帮助零售商在激烈的市场竞争中稳固立足,更能精准捕捉客户需求,实现利润最大化。以下,我们将深入探讨零售商…...
2024/5/1 13:01:46 - HIS系统是什么?一套前后端分离云HIS系统源码 接口技术RESTful API + WebSocket + WebService
HIS系统是什么?一套前后端分离云HIS系统源码 接口技术RESTful API WebSocket WebService 医院管理信息系统(全称为Hospital Information System)即HIS系统。 常规模版包括门诊管理、住院管理、药房管理、药库管理、院长查询、电子处方、物资管理、媒体管理等&…...
2024/5/1 13:22:01 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/5/1 17:30:59 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/5/2 16:16:39 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/4/29 2:29:43 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/5/3 23:10:03 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/4/27 17:58:04 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/4/27 14:22:49 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/4/28 1:28:33 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/4/30 9:43:09 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/4/27 17:59:30 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/5/4 18:20:48 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/4/28 1:34:08 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/4/26 19:03:37 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/4/29 20:46:55 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/4/30 22:21:04 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/5/1 4:32:01 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/5/4 2:59:34 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/4/28 5:48:52 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/4/30 9:42:22 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/5/2 9:07:46 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/4/30 9:42:49 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57