码迷,mamicode.com
首页 > 编程语言 > 详细

java--游戏后端--项目开发总结9--客户端--底层协议

时间:2019-05-31 18:09:52      阅读:138      评论:0      收藏:0      [点我收藏+]

标签:+=   handle   system   错误   lengthb   总结   else   cal   参数   

  1. 建立TCP连接
  2. 另起线程接收服务端消息
    1. 根据自己的消息设计规则进行消息的解码
    2. 解码出协议号
    3. 解码出参数
    4. 参数解码成具体的参数类
    5. 服务端主动推送的需要先注册方法
    6. 在保存表的协议字典中找出对应的表
    7. 调用回调方法
  3. 发送消息给服务端
    1. 将发送消息的lua表保存起来
    2. 组装消息发送给服务端
  4. 本底层为了扩展方便,使用了唯一的回调参数,此参数可进行任意变化与组合
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;
using XLua;

[LuaCallCSharp]
public class Client : MonoBehaviour {
    private const int TIMEOUT = 5000;//连接超时
    private Socket socket;//socket连接
    private Dictionary<int, LuaTable> responseCommandMap = new Dictionary<int, LuaTable>();//协议对象
    private const string RESPONSE_METHOD_NAME = "Response";//回调方法名称

    //连接服务器
    public void ConnectServe(string ip, int port) {
        socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//采用TCP方式连接
        IPAddress address = IPAddress.Parse(ip);//服务器IP地址
        IPEndPoint endpoint = new IPEndPoint(address, port);//服务器端口
        IAsyncResult result = socket.BeginConnect(endpoint, new AsyncCallback(ConnectCallback), socket);//异步连接,连接成功调用connectCallback方法
        bool success = result.AsyncWaitHandle.WaitOne(TIMEOUT, true);//连接超时的监测,当连接超过5秒还没成功表示超时
        if (!success) {
            Closed();//超时
            Debug.Log("连接超时");
        } else {
            //与socket建立连接成功,开启线程接受服务端数据。
            Thread thread = new Thread(new ThreadStart(ReceiveSorket));
            thread.IsBackground = true;
            thread.Start();
        }
    }

    //连接服务器回调
    private void ConnectCallback(IAsyncResult asyncConnect) {
    }

    //接收服务器消息
    private void ReceiveSorket() {
        //在这个线程中接受服务器返回的数据
        while (true) {
            if (!socket.Connected) {
                //与服务器断开连接跳出循环
                Debug.Log("与服务端断开连接");
                socket.Close();
                break;
            }
            try {
                //接受数据保存至bytes当中
                byte[] bytes = new byte[4096];
                //Receive方法中会一直等待服务端回发消息
                //如果没有回发会一直在这里等着。
                int i = socket.Receive(bytes);
                if (i <= 0) {
                    socket.Close();
                    break;
                }

                int length = 0;

                //协议号长度
                byte[] protocolIdLengthByte = new byte[4];
                Buffer.BlockCopy(bytes, length, protocolIdLengthByte, 0, protocolIdLengthByte.Length);
                length += protocolIdLengthByte.Length;
                int protocolIdLength = ByteUtil.Bytes2Int(protocolIdLengthByte);

                //协议号
                byte[] protocolIdByte = new byte[protocolIdLength];
                Buffer.BlockCopy(bytes, length, protocolIdByte, 0, protocolIdByte.Length);
                length += protocolIdByte.Length;
                int protocolId = ByteUtil.Bytes2Int(protocolIdByte);

                //参数长度
                byte[] parameterLengthByte = new byte[4];
                Buffer.BlockCopy(bytes, length, parameterLengthByte, 0, parameterLengthByte.Length);
                length += parameterLengthByte.Length;
                int parameterLength = ByteUtil.Bytes2Int(parameterLengthByte);

                //参数
                byte[] parameterByte = new byte[parameterLength];
                Buffer.BlockCopy(bytes, length, parameterByte, 0, parameterByte.Length);

                LoomUtil.QueueOnMainThread(() => {
                    LuaTable table;
                    responseCommandMap.TryGetValue(protocolId, out table);
                    if (null != table) {
                        table.Get<LuaFunction>(RESPONSE_METHOD_NAME).Call(table, ProtobufSerializerUtil.Deserialize<ParamList>(parameterByte));
                    } else {
                        Debug.LogError("未定义的协议号 = " + protocolId);
                    }
                });
            } catch (Exception e) {
                Debug.Log("连接中断" + e);
                socket.Close();
                break;
            }
        }
    }

    //关闭Socket
    private void Closed() {
        if (socket != null && socket.Connected) {
            socket.Shutdown(SocketShutdown.Both);
            socket.Close();
        }
        socket = null;
    }

    //退出程序
    void OnDestroy() {
        Closed();
        Debug.Log("关闭客户端,断开连接");
    }

    //向服务端发送数据
    public void SendRequest(string tableName, int protocolId, object obj) {
        //保存请求对象
        if (!responseCommandMap.ContainsKey(protocolId)) {
            string[] sArray = tableName.Split(new char[1] { / });
            responseCommandMap.Add(protocolId, LuaBehaviour.luaEnv.Global.Get<LuaTable>(sArray[sArray.Length - 1]));
        }

        List<byte[]> list = new List<byte[]>();

        //协议号
        byte[] protocolIdByte = ByteUtil.Int2Byte(protocolId);

        //协议号长度
        byte[] protocolIdLengthByte = new byte[4];
        protocolIdLengthByte = ByteUtil.Int2Byte(protocolIdByte.Length);

        //参数
        byte[] parameterByte = ProtobufSerializerUtil.Serialize(obj);
        //参数长度
        byte[] parameterLengthByte = new byte[4];
        parameterLengthByte = ByteUtil.Int2Byte(parameterByte.Length);

        //组装好的消息
        list.Add(protocolIdLengthByte);
        list.Add(protocolIdByte);
        list.Add(parameterLengthByte);
        list.Add(parameterByte);

        byte[] msg = ByteUtil.MergeByte(list);

        if (!socket.Connected) {
            socket.Close();
            Debug.Log("服务器断开连接");
            return;
        }
        try {
            IAsyncResult asyncSend = socket.BeginSend(msg, 0, msg.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket);
            bool success = asyncSend.AsyncWaitHandle.WaitOne(TIMEOUT, true);
            if (!success) {
                socket.Close();
                Debug.Log("发送失败");
            }
        } catch {
            Debug.Log("发送错误");
        }
    }

    //注册回调方法,此方法适用于服务端主动推送的协议
    public void RegisterResponse(string tableName, int protocolId) {
        //保存请求对象
        if (!responseCommandMap.ContainsKey(protocolId)) {
            string[] sArray = tableName.Split(new char[1] { / });
            responseCommandMap.Add(protocolId, LuaBehaviour.luaEnv.Global.Get<LuaTable>(sArray[sArray.Length - 1]));
        }
    }

    //发送回调
    private void SendCallback(IAsyncResult asyncConnect) {
    }
}

java--游戏后端--项目开发总结9--客户端--底层协议

标签:+=   handle   system   错误   lengthb   总结   else   cal   参数   

原文地址:https://www.cnblogs.com/plxz/p/10956663.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!