连接收发消息流程
服务端
//启动类
class Program
{static void Main(string[] args){//启动程序中创建一个Server类,传入ip和端口Server server = new Server("127.0.0.1", 6688);server.Start();Console.ReadKey();}
}//初始化Server
public Server(string ipStr,int port)
{//创建一个controllerManager管理类,用于管理不同类型的消息和动作的controllerManager类controllerManager = new ControllerManager(this);//设置服务器IP和端口SetIpAndPort(ipStr,port);
}//设置需要连接的IP和端口
public void SetIpAndPort(string ipStr,int port)
{ //创建一个IP对象ipEndPoint = new IPEndPoint(IPAddress.Parse(ipStr), port);
}//创建Socket类
public void Start()
{//创建一个socket对象serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp);//绑定ip和端口serverSocket.Bind(ipEndPoint);//开启最大监听数,0表示没有限制serverSocket.Listen(0);//开始接受连接serverSocket.BeginAccept(AcceptCallBack,null);
}//收到连接的回调
private void AcceptCallBack(IAsyncResult ar)
{//得到一个客户端的连接Socket clientSocket = serverSocket.EndAccept(ar);//创建服务端的一个Client与客户端对应,并且将clientSocket传入,用于消息的收发Client client = new Client(clientSocket,this);//初始化客户端client.Start();//将连接的客户端增加到list中进行管理clientList.Add(client);//继续开始下一个连接的监听serverSocket.BeginAccept(AcceptCallBack,null);
}//Client类
public void Start()
{if(clientSocket==null ||clientSocket.Connected==false){return;}//开启消息的监听,设置消息接收的回调clientSocket.BeginReceive(msg.Data, msg.StartIndex, msg.RemainSize, SocketFlags.None,ReceviceCallBack,null);
}//Client类中消息接收
private void ReceviceCallBack(IAsyncResult ar)
{try{if ( clientSocket == null || clientSocket.Connected == false){return;}int count = clientSocket.EndReceive(ar);if (count == 0){Close();}//处理接收到的数据,这里的处理和客户端接收到消息后一致(客户端写的比较详细)msg.ReadMessage(count,OnProcessMessage);Start();//clientSocket.BeginReceive(null, 0, 0, SocketFlags.None, ReceviceCallBack, null);}catch(Exception e){Console.WriteLine(e);Close();}
}//创建一个解析完消息的回调函数,Client类中的private void OnProcessMessage(RequestCode requestCode,ActionCode actionCode,string data){server.HandleRequest(requestCode, actionCode, data, this);}//Server类中的
public void HandleRequest(RequestCode requestCode, ActionCode actioncode, string data, Client client)
{//通过controllerManager调用不同的controllerManager类来处理不同的请求和动作controllerManager.HandleRequest(requestCode, actioncode, data, client);
}//controllerManager类中的
public void HandleRequest(RequestCode requestCode,ActionCode actionCode,string data,Client client)
{BaseController controller;//通过requestCode找到不同的controller类bool isGet = controllerDict.TryGetValue(requestCode, out controller);if(isGet == false){Console.WriteLine("无法得到" + requestCode + "所对应的Controller,无法处理请求");return;}//通过actionCode找到对应的方法名string methodName = Enum.GetName(typeof(ActionCode), actionCode);//根据得到的controller类和methodName得到方法MethodInfo mi = controller.GetType().GetMethod(methodName);if(mi == null){Console.WriteLine("[警告]在Controller[" + controller.GetType() + "]中没有对应的处理方法:[" + methodName + "]");}//创建一个参数类型,参数中包含了数据,客户端,服务端object[] parameters = new object[] { data,client,server };//调用对应controller类中的对应方法,传入参数,得到处理后的结果object o = mi.Invoke(controller, parameters);if (o == null || string.IsNullOrEmpty(o as string)) {Console.WriteLine("return 掉了吗");return;}//通过Server统一回复消息给客户端server.SendResponse(client, actionCode, o as string);
}//sever中的类//这个函数是controllerManager处理完消息后,调用此方法,发送消息给客户端public void SendResponse(Client client,ActionCode actionCode,string data){//通过形参调用对应的client进行消息的发送client.Send(actionCode, data);}
- 创建一个Server对象
- 将IP和端口作为参数传入
- 创建一个ControllerManager类,用于对不同类型的controller进行管理
- 根据传入的IP和端口创建一个IP对象
- 创建一个Socket对象,绑定IP对象开启连接监听。设置连接后的回调函数
- 连接后,创建一个与客户端对应的client,将socket对象和自身传入,用于后续消息的收发,将client放到list中进行管理
客户端(MVC)
//创建一个GameFacade类,继承自MonoBehaviourpublic class GameFacade : MonoBehaviour {//Awake中设置分辨率private void Awake(){Screen.SetResolution(1280, 800, false);}void Start (){//初始化各种管理类InitManager();}private void InitManager(){//UI框架类uiManager = new UIManager(this);//相机类,用于显示和跟随cameraManager = new CameraManager(this);//音效类audioManager = new AudioManager(this);//玩家类playerManager = new PlayerManager(this);//消息类requestManager = new RequestManager(this);//客户端管理类clientManager = new ClientManager(this);//各个Manager类进行初始化uiManager.OnInit();cameraManager.OnInit();audioManager.OnInit();playerManager.OnInit();requestManager.OnInit();clientManager.OnInit();}//用于对每个管理类进行updatevoid Update(){UpdateManager();if(isEnterPlay){EnterPlaying();isEnterPlay = false;}}}//与服务端的连接主要是ClientManager中//定义IP和端口
private const string IP = "127.0.0.1";
private const int PORT = 6688;
//消息对象,用于对消息的解析
private Message msg = new Message();//对ClientManager进行初始化
public override void OnInit()
{//调用基类的初始化函数base.OnInit();//创建一个Socket连接clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);try{//连接服务器clientSocket.Connect(IP, PORT);Start();}catch(Exception e){Debug.LogWarning("无法连接到服务器端,清检查你的网络!!" + e);}}private void Start()
{ //开启消息的监听,将消息存入之前定义的msg,得到内容,开始index,clientSocket.BeginReceive(msg.Data,msg.StartIndex,msg.,SocketFlags.None,ReceiveCallback,null);
}//接收到消息的回调,这个不是在主线程中,需要访问unity的组件什么的,需要在主线程访问
private void ReceiveCallback(IAsyncResult ar)
{//Debug.LogWarning("接收到一条数据:");try{if(clientSocket==null ||clientSocket.Connected==false){return;}//获取消息的长度int count = clientSocket.EndReceive(ar);//读取消息内容msg.ReadMessage(count, OnProcessDataCallback);Start();}catch(Exception e){Debug.Log(e);}
}//消息类的读取消息函数
//解析数据,客户端解析数据没有actionCode,服务端只会传消息号和内容。
public void ReadMessage(int newDataAmount, Action processDataCallBack)
{startIndex += newDataAmount;while (true){if (startIndex <= 4){return;}//解析出数据总长,int数据类型int count = BitConverter.ToInt32(data, 0);if ((startIndex - 4) >= count){//解析出requesCode,这里的actionCode 类型是枚举类型,用 as 方式转型不行,采用强制转型的方式。ActionCode actionCode = (ActionCode)BitConverter.ToInt32(data, 4);//解析出数据string s = Encoding.UTF8.GetString(data, 8, count - 4);if(actionCode!=ActionCode.Move){Console.WriteLine("解析出来一条数据:" + actionCode + s);}//触发回调,传入动作类型和数据processDataCallBack(actionCode, s);Array.Copy(data, count + 4, data, 0, startIndex - 4 - count);startIndex -= (count + 4);}else{break;}}
}private void OnProcessDataCallback(ActionCode actionCode,string data)
{//调用facade的HandleReponse函数对消息进行统一的处理facade.HandleReponse(actionCode, data);
}//gamefacade类中的函数
public void HandleReponse(ActionCode actionCode, string data)
{//调用requestManager中的HandleReponse方法,根据传入的actionCode来调用对应类中的方法requestManager.HandleReponse(actionCode, data);
}//requestManager中的类
public void HandleReponse(ActionCode actionCode,string data)
{//从字典中找到对应的类BaseRequest request = requestDict.TryGet(actionCode);if(actionCode!=ActionCode.Move){Debug.LogWarning("接收一条消息:\n" + "动作:" + actionCode + " 数据:" + data);}if (request == null){Debug.LogWarning("无法得到ActionCode[" + actionCode + "]对应的方法");return;}//调用对应类的OnResponse函数request.OnResponse(data);
}//以ShowTimerRequest为例
public override void OnResponse(string data)
{int time = int.Parse(data);//界面根据服务端数据返回进行展示gamePanel.ShowTimeSync(time);
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!