网络游戏连接、收发消息流程

连接收发消息流程

服务端

//启动类
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);
    }
  1. 创建一个Server对象
  2. 将IP和端口作为参数传入
  3. 创建一个ControllerManager类,用于对不同类型的controller进行管理
  4. 根据传入的IP和端口创建一个IP对象
  5. 创建一个Socket对象,绑定IP对象开启连接监听。设置连接后的回调函数
  6. 连接后,创建一个与客户端对应的client,将socket对象和自身传入,用于后续消息的收发,将client放到list中进行管理

客户端(MVC)

//创建一个GameFacade类,继承自MonoBehaviour
 public 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();
    }
    
    //用于对每个管理类进行update
    void 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<ActionCode, string> 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,BaseRequest>(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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值