Socket多人联网游戏学习记录
2018-02-09 12:55
232 查看
连接Mysql 准备
创建数据库Test001创建一个表,TableName为user
创建新列,id(设置为主键,勾选PK NN AI),username,password
查询刚才新建的表格Select Row
添加新数据
使用mysql插件,找到mysql安装目录,C:\Program Files (x86)\MySQL\Connector.NET 6.9\Assemblies\v4.5\MySql.Data.dll(选择相近版本)
查询数据库
首先导入,数据库连接插件,引入Mysql.Data.MysqlClientusing System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using MySql.Data.MySqlClient; namespace MySqlTest { class Program { static void Main(string[] args) { string connStr = "Database=test001;Data Source=127.0.0.1;port=3306;user=root;pwd=root;"; //连接数据库语句(忽略大小写) MySqlConnection conn = new MySqlConnection(connStr); //创建连接对象 conn.Open(); //打开通道 //MySqlCommand cmd = new MySqlCommand("select * from user where id = 1", conn); //读取id为 1的记录 MySqlCommand cmd = new MySqlCommand("select * from user", conn); MySqlDataReader reader= cmd.ExecuteReader(); //执行查询记录 //if(reader.HasRows) //判断数据是否为空 //{ // reader.Read(); //只读取一行表数据 // //获取数据 // string username = reader.GetString("username"); // string password = reader.GetString("password"); // Console.WriteLine("username:" + username); // Console.WriteLine("password:" + password); //} while (reader.Read()) //行数据不为空,一直执行 { //获取数据 string username = reader.GetString("username"); string password = reader.GetString("password"); Console.WriteLine("username:" + username); Console.WriteLine("password:" + password); } //关闭数据流 reader.Close(); conn.Close(); Console.ReadKey(); } } }
插入数据
插入数据时,要防止sql注入问题。//注意 Sql注入问题 string user = "newUser"; string pwd = "newPwd"; MySqlCommand cmd = new MySqlCommand("insert into user set username=@user,password=@pwd", conn); //@符号后面是用户自定义的插入内容 cmd.Parameters.AddWithValue("user", user); //数值绑定 cmd.Parameters.AddWithValue("pwd", pwd); cmd.ExecuteNonQuery(); //执行非查询命令
删除数据
MySqlCommand cmd = new MySqlCommand("delete from user where id =@id", conn); cmd.Parameters.AddWithValue("id", 3); //删除id为3的记录 cmd.ExecuteNonQuery();
更新数据
//更新id为 2 的密码为“updatePsd” string pwd = "updatePsd"; MySqlCommand cmd = new MySqlCommand("update user set password=@pwd where id = 2", conn); cmd.Parameters.AddWithValue("pwd", pwd); cmd.ExecuteNonQuery();
游戏服务器端口分层架构
ControllerDAO
Model
Server
Tool
Client不和Controller直接交互,需要通过Server间接处理数据
数据封装打包处理
定义一个Action方法,讲解析出的RequestCode,Data和数据长度,注入这个方法中。外部可以通过回调函数直接拿到处理过的数据。/// <summary> /// 解析数据或者叫做读取数据 /// </summary> public void ReadMessage(int newDataAmount,Action<RequestCode,ActionCode,string> processDataCallBack) //参数用于传递解析出来的数据 { startIndex += newDataAmount; while (true) { if (startIndex <= 4) return; int count = BitConverter.ToInt32(data, 0); if ((startIndex - 4) >= count) { //Console.WriteLine(startIndex); //Console.WriteLine(count); //string s = Encoding.UTF8.GetString(data, 4, count); //Console.WriteLine("解析出来一条数据:" + s); //RequestCode占前4位,ActionCode占4位,data从第12位开始 RequestCode requestCode=(RequestCode) BitConverter.ToInt32(data, 4); ActionCode actionCode = (ActionCod 4000 e)BitConverter.ToInt32(data, 8); string s = Encoding.UTF8.GetString(data, 12, count - 8); processDataCallBack(requestCode, actionCode, s); Array.Copy(data, count + 4, data, 0, startIndex - 4 - count); startIndex -= (count + 4); } else { break; } } }
外部:
//TODO 处理接收到的数据 msg.ReadMessage(count,OnProcessMessage); //处理前四个字节的校验位
//ReadMessage 的回调函数,每次读取消息都会调用此方法 private void OnProcessMessage(RequestCode requestCode,ActionCode actionCode,string data) { server.HandleRequest(requestCode,actionCode,data,this); //不在客户端处理数据 }
创建客户端和服务器共享文件Common
namespace Common { public enum ActionCode { None, } }
/// <summary> /// Commom 类库,服务端和客户端共同使用 /// </summary> namespace Common { //每一个RequestCode对应一个Controller处理相关事件 public enum RequestCode { None, } }
ControllerManager 统一管理客户端对应Controller
Client读取服务器发来的数据,把相关回复方法交给对应的Controller处理。相关ControllerManager代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Common; using System.Reflection; using GameServer.Servers; /// <summary> /// 此类之和server交互 /// </summary> namespace GameServer.Controller { class ControllerManager { private Dictionary<RequestCode, BaseController> controllerManager = new Dictionary<RequestCode, BaseController>(); //存储所有的controller private Server server; //因为server经常需要被访问,所以应该制作成单独变量 public ControllerManager(Server server) { this.server = server; InitController(); } private void InitController() { DefaultController defaultController = new DefaultController(); controllerManager.Add(defaultController.RequestCode, defaultController); //默认的控制器 } //通过RequestCode来找到对应的ActionCode,然后执行方法调用 public void HandleRequest(RequestCode requestCode, ActionCode actionCode, string data, Client client) { BaseController controller; bool isGet = controllerManager.TryGetValue(requestCode, out controller); //尝试查找requestCode if (isGet == false) { Console.WriteLine("无法得到[" + requestCode + "]所对应的Controller"); return; } string methodName = Enum.GetName(typeof(ActionCode), actionCode); //找到对应的方法 MethodInfo mi = controller.GetType().GetMethod(methodName); //在Controller下面执行此ActionCode对应的方法 if (mi == null) { Console.WriteLine("在Controller[" + controller.GetType() + "]中没有对应的处理方法:" + methodName); return; } object[] parameters = new object[] { data, client, server }; object o = mi.Invoke(controller, parameters); if (o == null||string.IsNullOrEmpty(o as string)) { return; } server.SendResponse(client, requestCode, o as string);//向服务器发送请求的方法 } } }
客户端架构
BaseManager:包括UIManager,CameraManager,AudioManager,PlayerManager,RequestManager(管理所有请求)ClientManager(这个用来管理跟服务器端连接的socket)。用来统一管理以上的控制器。
GameFacade:包括BaseManager。GameFacade 充当外观者或中介者,各个模块的交互通过Facade来进行,可以减少耦合性。
BaseManager管理所有控制器
创建一个带有GameFacade参数的构造方法,在子类中可以使用GameFacade来与其他Manager模块交互。using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 用来管理所有的Manager /// </summary> public class BaseManager { protected GameFacade facade; //受保护类型,只能被子类调用 public BaseManager(GameFacade facade) { this.facade = facade; } public virtual void OnInit() { } public virtual void OnDestroy() { } }
子类在重写的时候,也应该重写父类的构造方法。
public UIManager(GameFacade facade) : base(facade) { ParseUIPanelTypeJson(); }
GameFacade中介者
创建GameFacade来访问其他模块的代码,从而减少代码之前的耦合性,方便后期代码的的升级和修改。继承至MonoBehaviour,当代码挂载到游戏物体身上使时,完成OnInit的初始化。using System.Collections; using System.Collections.Generic; using UnityEngine; using Common; /// <summary> /// 用于不同Manager之间的交互的 /// </summary> public class GameFacade:MonoBehaviour { private static GameFacade _instance; public static GameFacade Instance //单例 { get { return _instance; } } private UIManager uiMng; private AudioManager audioMng; private PlayerManager playerMng; private CameraManager cameraMng; private RequestManager requesrMng; private ClientManager clientMng; private void Awake() { if(_instance!=null) { Destroy(this.gameObject); return; } else { _instance = this; } } // Use this for initialization void Start () { InitManager(); } //生命周期 private void InitManager() { //初始化 uiMng = new UIManager(this); audioMng = new AudioManager(this); playerMng = new PlayerManager(this); cameraMng = new CameraManager(this); requesrMng = new RequestManager(this); clientMng = new ClientManager(this); uiMng.OnInit(); audioMng.OnInit(); playerMng.OnInit(); cameraMng.OnInit(); requesrMng.OnInit(); clientMng.OnInit(); } private void DestroyManager() { uiMng.OnDestroy(); audioMng.OnDestroy(); playerMng.OnDestroy(); cameraMng.OnDestroy(); requesrMng.OnDestroy(); clientMng.OnDestroy(); } private void OnDestroy() { DestroyManager(); } public void AddRequest(RequestCode requestCode, BaseRequest baseRequest) { requesrMng.AddRequest(requestCode, baseRequest); } public void RemoveRequest(RequestCode requestCode) { requesrMng.RemoveRequest(requestCode); } public void HandleReponse(RequestCode requestCode, string data) { requesrMng.HandleReponse(requestCode,data); } }
客户端的Message方法修改
因为客户端在打包数据的时候需要把RequestCode,ActionCode和数据打包在一起发送到服务器端。所有修改以下代码片段:using System; using System.Collections.Generic; using System.Linq; using System.Text; using Common; public class Message { private byte[] data = new byte[1024]; private int startIndex = 0;//我们存取了多少个字节的数据在数组里面 //public void AddCount(int count) //{ // startIndex += count; //} public byte[] Data { get { return data; } } public int StartIndex { get { return startIndex; } } public int RemainSize { get { return data.Length - startIndex; } } /// <summary> /// 解析数据或者叫做读取数据 /// </summary> public void ReadMessage(int newDataAmount, Action<RequestCode, string> processDataCallBack) //参数用于传递解析出来的数据 { startIndex += newDataAmount; while (true) { if (startIndex <= 4) return; int count = BitConverter.ToInt32(data, 0); if ((startIndex - 4) >= count) { //Console.WriteLine(startIndex); //Console.WriteLine(count); //string s = Encoding.UTF8.GetString(data, 4, count); //Console.WriteLine("解析出来一条数据:" + s); //RequestCode占前4位,ActionCode占4位,data从第12位开始 RequestCode requestCode = (RequestCode)BitConverter.ToInt32(data, 4); //ActionCode actionCode = (ActionCode)BitConverter.ToInt32(data, 8); string s = Encoding.UTF8.GetString(data, 8, count - 4); processDataCallBack(requestCode, s); Array.Copy(data, count + 4, data, 0, startIndex - 4 - count); startIndex -= (count + 4); } else { break; } } } /// <summary> /// 封装 数据长度,RequestCode,data 为字节流 /// </summary> /// <param name="requestCode"></param> /// <param name="data"></param> public static byte[] PackData(RequestCode requestCode, string data) //类似工具方法,可以使用static方便调用 { byte[] requestCodeBytes = BitConverter.GetBytes((int)requestCode); byte[] dataBytes = Encoding.UTF8.GetBytes(data); int dataAmount = requestCodeBytes.Length + dataBytes.Length; byte[] dataAmountBytes = BitConverter.GetBytes(dataAmount); return (byte[])dataAmountBytes.Concat(requestCodeBytes).Concat(dataBytes); } //客户端发送的方法 public static byte[] PackData(RequestCode requestCode,ActionCode actionCode, string data) //类似工具方法,可以使用static方便调用 { byte[] requestCodeBytes = BitConverter.GetBytes((int)requestCode); byte[] actionCodeBytes = BitConverter.GetBytes((int)actionCode); byte[] dataBytes = Encoding.UTF8.GetBytes(data); int dataAmount = requestCodeBytes.Length + dataBytes.Length+actionCodeBytes.Length; byte[] dataAmountBytes = BitConverter.GetBytes(dataAmount); return (byte[])dataAmountBytes.Concat(requestCodeBytes).Concat(actionCodeBytes).Concat(dataBytes); //数据长度,RequestCode,ActionCode,数据 } }
UI框架的使用
在使用UI框架的时候,一定要注意命名的规范性,这将也是我们能否快速开发的关键因素。每一个Panel面板都需要创建一个同名脚本拿来管理这个面板,此脚步需要继承自BasePanel
将创建好的面板做成Prefab,放到Resources文件夹下
修改UIPanelType.cs脚本
修改UIPanelType.json脚本(存储面板所在路径)
取消UIManager的单例模式,继承自BaseManager管理
UIManager通过构造方法得到GameGacade的引用,通过重写父类的OnInit方法来初始化
BaseManager:
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 用来管理所有的Manager /// </summary> public class BaseManager { protected GameFacade facade; //受保护类型,只能被子类调用 public BaseManager(GameFacade facade) { this.facade = facade; } public virtual void OnInit() { } public virtual void OnDestroy() { } }
UiManager:
using UnityEngine; using System.Collections; using System.Collections.Generic; using System; public class UIManager:BaseManager { public UIManager(GameFacade facade) : base(facade) { ParseUIPanelTypeJson(); } public override void OnInit() //在GameFacade调用 { base.OnInit(); PushPanel(UIPanelType.Message); PushPanel(UIPanelType.Start); } /// /// 单例模式的核心 /// 1,定义一个静态的对象 在外界访问 在内部构造 /// 2,构造方法私有化 //private static UIManager _instance; //public static UIManager Instance //{ // get // { // if (_instance == null) // { // _instance = new UIManager(); // } // return _instance; // } //} private Transform canvasTransform; private Transform CanvasTransform { get { if (canvasTransform == null) { canvasTransform = GameObject.Find("Canvas").transform; } return canvasTransform; } } private Dictionary<UIPanelType, string> panelPathDict;//存储所有面板Prefab的路径 private Dictionary<UIPanelType, BasePanel> panelDict;//保存所有实例化面板的游戏物体身上的BasePanel组件 private Stack<BasePanel> panelStack; private MessagePanel msgPanel; /// <summary> /// 把某个页面入栈,把某个页面显示在界面上 /// </summary> public void PushPanel(UIPanelType panelType) { if (panelStack == null) panelStack = new Stack<BasePanel>(); //判断一下栈里面是否有页面 if (panelStack.Count > 0) { BasePanel topPanel = panelStack.Peek(); topPanel.OnPause(); //暂停栈顶的UI } //实例化UI界面 BasePanel panel = GetPanel(panelType); panel.OnEnter(); panelStack.Push(panel); //加入新的UI } /// <summary> /// 出栈 ,把页面从界面上移除 /// </summary> public void PopPanel() { if (panelStack == null) panelStack = new Stack<BasePanel>(); if (panelStack.Count <= 0) return; //关闭栈顶页面的显示 BasePanel topPanel = panelStack.Pop(); topPanel.OnExit(); if (panelStack.Count <= 0) return; BasePanel topPanel2 = panelStack.Peek(); topPanel2.OnResume(); } /// <summary> /// 根据面板类型 得到实例化的面板 /// </summary> /// <returns></returns> private BasePanel GetPanel(UIPanelType panelType) { if (panelDict == null) { panelDict = new Dictionary<UIPanelType, BasePanel>(); } //BasePanel panel; //panelDict.TryGetValue(panelType, out panel);//TODO BasePanel panel = panelDict.TryGet(panelType); if (panel == null) { //如果找不到,那么就找这个面板的prefab的路径,然后去根据prefab去实例化面板 //string path; //panelPathDict.TryGetValue(panelType, out path); string path = panelPathDict.TryGet(panelType); GameObject instPanel = GameObject.Instantiate(Resources.Load(path)) as GameObject; instPanel.transform.SetParent(CanvasTransform,false); instPanel.GetComponent<BasePanel>().UIMng= this; //实例化UIManager panelDict.Add(panelType, instPanel.GetComponent<BasePanel>()); return instPanel.GetComponent<BasePanel>(); } else { return panel; } } [Serializable] class UIPanelTypeJson { public List<UIPanelInfo> infoList; } private void ParseUIPanelTypeJson() { panelPathDict = new Dictionary<UIPanelType, string>(); TextAsset ta = Resources.Load<TextAsset>("UIPanelType"); UIPanelTypeJson jsonObject = JsonUtility.FromJson<UIPanelTypeJson>(ta.text); foreach (UIPanelInfo info in jsonObject.infoList) { //Debug.Log(info.panelType); panelPathDict.Add(info.panelType, info.path); } } //给MsgPaneld赋值 public void InjectMsgPanel(MessagePanel msgPanel) { this.msgPanel = msgPanel; } public void ShowMessage(string msg) { if(msgPanel==null) { Debug.Log("无法显示提示信息,MsgPanel为空"); } else { msgPanel.ShowMessage(msg); } } public void ShowMessageSync(string msg) { if (msgPanel == null) { Debug.Log("无法显示提示信息,MsgPanel为空"); } else { msgPanel.ShowMessageSync(msg); } } /// <summary> /// just for test /// </summary> //public void Test() //{ // string path ; // panelPathDict.TryGetValue(UIPanelType.Knapsack,out path); // Debug.Log(path); //} }
GameFacede:
using System.Collections; using System.Collections.Generic; using UnityEngine; using Common; /// <summary> /// 用于不同Manager之间的交互的 /// </summary> public class GameFacade:MonoBehaviour { private static GameFacade _instance; public static GameFacade Instance //单例 { get { return _instance; } } private UIManager uiMng; private AudioManager audioMng; private PlayerManager playerMng; private CameraManager cameraMng; private RequestManager requesrMng; private ClientManager clientMng; private void Awake() { if(_instance!=null) { Destroy(this.gameObject); return; } else { _instance = this; } } // Use this for initialization void Start () { InitManager(); } //生命周期 private void InitManager() { //初始化 uiMng = new UIManager(this); audioMng = new AudioManager(this); playerMng = new PlayerManager(this); cameraMng = new CameraManager(this); requesrMng = new RequestManager(this); clientMng = new ClientManager(this); uiMng.OnInit(); audioMng.OnInit(); playerMng.OnInit(); cameraMng.OnInit(); requesrMng.OnInit(); clientMng.OnInit(); } private void DestroyManager() { uiMng.OnDestroy(); audioMng.OnDestroy(); playerMng.OnDestroy(); cameraMng.OnDestroy(); requesrMng.OnDestroy(); clientMng.OnDestroy(); } private void OnDestroy() { DestroyManager(); } public void AddRequest(ActionCode actionCode, BaseRequest baseRequest) { requesrMng.AddRequest(actionCode, baseRequest); } public void RemoveRequest(ActionCode actionCode) { requesrMng.RemoveRequest(actionCode); } public void HandleReponse(ActionCode actionCode, string data) { requesrMng.HandleReponse(actionCode, data); } public void ShowMessage(string msg) { uiMng.ShowMessage(msg); } public void SendRequest(RequestCode requestCode, ActionCode actionCode, string data) { clientMng.SendRequest(requestCode, actionCode, data); } }
UI面板的切换
UIManager首先加载了UIPanelType.Start的面板,对应面板的按钮交互放在对应Panel 脚本下面。StartPanel:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using DG.Tweening; public class StartPanel : BasePanel { private Button loginButton; private Animator loginAnim; public override void OnEnter() { base.OnEnter(); loginButton = transform.Find("LoginButton").GetComponent<Button>(); loginAnim = loginButton.GetComponent<Animator>(); loginButton.onClick.AddListener(OnLoginCLick); //注册点击事件 //loginButton.transform.DOScale(1, 0.5f); } private void OnLoginCLick() { uiMng.PushPanel(UIPanelType.Login); //加载登录面板 } }
通过RequestCode区分Controller
通过ActionCode区分Request
LoginPanel:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using DG.Tweening; using Common; public class LoginPanel : BasePanel { private Button closeButton; //关闭按钮 private Button loginButton; //登录按钮 private InputField userInput; private InputField pwdInput; private LoginRequest loginRequest; //登录脚本 void Start() { userInput = transform.Find("UsernameLabel/UsernameInput").GetComponent<InputField>(); pwdInput = transform.Find("PasswordLabel/PasswordInput").GetComponent<InputField>(); closeButton = transform.Find("CloseButton").GetComponent<Button>(); closeButton.onClick.AddListener(OnClsoeButton); loginButton = transform.Find("LoginButton").GetComponent<Button>(); loginButton.onClick.AddListener(OnLoginClick); loginRequest = GetComponent<LoginRequest>(); } //登录校验 private void OnLoginClick() { string msg = ""; if(string.IsNullOrEmpty(userInput.text)) { msg += "用户名不能为空 "; } if(string.IsNullOrEmpty(pwdInput.text)) { msg += "密码不能为空"; } if(msg!="") { uiMng.ShowMessage(msg); return; } //TODO请求服务器端 loginRequest.SendRequest(userInput.text, pwdInput.text); } public void OnLoginResponse(ReturnCode returnCode) { if(returnCode==ReturnCode.Success) { //TODO登录成功 Debug.Log("登录成功!"); } else { uiMng.ShowMessageSync("用户名或密码错误,请重新输入!"); } } private void OnClsoeButton() { //print("关闭"); uiMng.PopPanel(); } public override void OnEnter() { base.OnEnter(); ShowPanel(); } private void ShowPanel() { gameObject.SetActive(true); RectTransform rectPos = GetComponent<RectTransform>(); Vector3 temp = rectPos.position; temp.x = -1000; rectPos.position = temp; //把物体移到外边 rectPos.DOAnchorPosX(0, 0.5f); //移到目的地 transform.DOScale(1, 0.5f); } private void HidePanel() { transform.DOScale(0, 0.5f); transform.DOLocalMoveX(-1000, 0.5f).OnComplete(() => gameObject.SetActive(false)); } public override void OnExit() { base.OnExit(); HidePanel(); } public override void OnResume() { base.OnResume(); ShowPanel(); } //public override void OnPause() //{ // base.OnPause(); // HidePanel(); //} }
服务器响应请求:
Server:
public Server() { } public Server(string ipStr,int port) { controllerManager = new ControllerManager(this); SetIpEndPort(ipStr,port); } public void SetIpEndPort(string ipStr,int port) { ipEndPort = new IPEndPoint(IPAddress.Parse(ipStr), port); } public void Start() //启动监听 { serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); serverSocket.Bind(ipEndPort); //绑定ip和端口号 serverSocket.Listen(0); //一直监听 serverSocket.BeginAccept(AcceptCallBack, null); //回掉 } private void AcceptCallBack(IAsyncResult ar) { Socket clientSocket = serverSocket.EndAccept(ar); //获得客户端的连接 Client client = new Client(clientSocket,this); client.Start(); clientList.Add(client); }
Client:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Net.Sockets; using Common; using MySql.Data.MySqlClient; using GameServer.Tool; namespace GameServer.Servers { class Client { private Socket clientSocket; //存储获取连接的Socket private Server server; //server的相关处理 private Message msg = new Message(); //创建一个字符处理类(处理前四个字节的校验位) private MySqlConnection mysqlConn; //使对应Controller来获取mysql连接,从而进行一些操作 public MySqlConnection MySqlConn { get { return mysqlConn; } } public Client() { } public Client(Socket clientSocket,Server server) //在client初始化server { this.clientSocket = clientSocket; this.server = server; mysqlConn = ConnHelper.Connect(); //初始化数据库连接 } public void Start() { //客户端接收缓存 clientSocket.BeginReceive(msg.Data, msg.StartIndex, msg.RemainSize, SocketFlags.None, ReceiveCallBack, null); //客户端开启监听 } private void ReceiveCallBack(IAsyncResult ar) { try { int count = clientSocket.EndReceive(ar); if (count == 0) //偏移量为0 { Close(); } //TODO 处理接收到的数据 msg.ReadMessage(count,OnProcessMessage); //处理前四个字节的校验位 Start(); } catch(Exception e) { Console.WriteLine(e); Close(); } } //ReadMessage 的回调函数,每次读取消息都会调用此方法 private void OnProcessMessage(RequestCode requestCode,ActionCode actionCode,string data) { server.HandleRequest(requestCode,actionCode,data,this); //不在客户端处理数据 } private void Close() //断开连接 { ConnHelper.CloseConnectiom(mysqlConn); //关闭数据库连接 if (clientSocket != null) clientSocket.Close(); server.RemoveClient(this); //从服务器连接的客户端的集合移除 } public void Send(ActionCode actionCode,string data) { byte[] bytes = Message.PackData(actionCode, data); clientSocket.Send(bytes); } } }
ControllerManager数据处理:
//通过RequestCode来找到对应的ActionCode,然后执行方法调用 public void HandleRequest(RequestCode requestCode, ActionCode actionCode, string data, Client client) { BaseController controller; bool isGet = controllerManager.TryGetValue(requestCode, out controller); //尝试查找requestCode if (isGet == false) { Console.WriteLine("无法得到[" + requestCode + "]所对应的Controller"); return; } string methodName = Enum.GetName(typeof(ActionCode), actionCode); //找到对应的方法 MethodInfo mi = controller.GetType().GetMethod(methodName); //在Controller下面执行此ActionCode对应的方法 if (mi == null) { Console.WriteLine("在Controller[" + controller.GetType() + "]中没有对应的处理方法:" + methodName); return; } object[] parameters = new object[] { data, client, server }; object o = mi.Invoke(controller, parameters); if (o == null||string.IsNullOrEmpty(o as string)) { return; } server.SendResponse(client, actionCode, o as string);//向服务器发送请求的方法 }
这就是封装啊,登录请求继承请求基础类,请求调用发送方法,发送方法属于游戏底层的类,底层又归游戏管理类管理
相关文章推荐
- Socket多人联网游戏学习记录2
- CocosCreator游戏开发---菜鸟学习之路(二)SocketIO简易教程
- (学习日记)数据结构第一章中life游戏开发的学习记录
- Python Socket学习记录
- 【java学习记录】12.用Socket网络访问方法,实现简单的网络聊天程序
- 【android学习记录】socket 连接两个android设备 服务器端
- Andriod 游戏编程 学习记录2
- Head First Java (第二版)学习记录 5 - 编写程序 DotCom 初级游戏
- Andriod 游戏编程 学习记录2
- MaNGOS-Zero源码学习之mangosd游戏逻辑服务器(二):socket的处理方式
- 【android 学习记录】socket客户端
- python 学习记录(4)—本金+利息计算及简单的游戏猜测程序
- Python学习记录-socket编程
- 游戏编程框架学习记录
- Socket.io应用之联网拖拽游戏
- Unity3D学习记录——飞盘射击游戏1
- 游戏开发记录120811:cocos2d-x引擎学习---目录结构及主要类
- 【Android】学习记录socket 再
- android学习:游戏开发(只做记录,不做学习资料)
- PHP Socket 学习记录client service