Unity中使用Mqtt协议进行通信

常见游戏后端

BackEnd支持协议越来越多,比如HTTP、TCP、UDP、MQTT等。各协议各有优点。

mqant框架

可以使用Module对Beego进行封装。

注意:使用_ "cpvrtapp/routers”进行初始化,不然是不能行的,没有调用Init

MQTTNet

https://github.com/landbroken/MQTTLearning

做为最基础的协议支持吧。

服务器其它组件看情况支持。

ET这个支持加NetCore2.1,看样子不错的

https://github.com/egametang/ET

ENet

扫描二维码关注公众号,回复: 10310888 查看本文章

英雄联盟据说也用这个

https://github.com/RainsSoft/ENetSharp

一个C#的封装

ENET库 https://github.com/lsalzman/enet

c#包装1:https://github.com/RainsSoft/enetcs

c#包装2:https://github.com/RainsSoft/ENetSharp

MQTT的介绍Baidu一下就可以了。

MQTT

本文重点介绍一下MQTT在Unity中的使用。

其中重要概念就是话题(Topic)、这里为会与HTTP对比,可以把它看是URL。它也是分层的。主要格式与概念如下:

  主题层级分隔符  / :     用于分割主题层级,/分割后的主题,这是消息主题层级设计中很重要的符号。   比方说: aaa/bbb和  aaa/bbb/ccc 和aaa/bbb/ccc/ddd  ,这样的消息主题格式,是一个层层递进的关系,可通过多层通配符同时匹配两者,或者单层通配符只匹配一个。  这在现实场景中,可以应用到:公司的部门层级推送、国家城市层级推送等包含层级关系的场景。

         单层通配符  +:      单层通配符只能匹配一层主题。比如:   aaa/+     可以匹配 aaa/bbb ,但是不能匹配aaa/bbb/ccc。   单独的+号可以匹配单层的所有推送。

        多层通配符  #:   多层通配符可以匹配于多层主题。比如: aaa/#   不但可以匹配aaa/bbb,还可以匹配aaa/bbb/ccc/ddd。  也就是说,多层通配符可以匹配符合通配符之前主题层级的所有子集主题。单独的#匹配所有的消息主题.
 

有关代码实现以上通配符的比较,还需要进行正则表达式进行匹配,参考如下:

https://www.cnblogs.com/liter7/p/5175012.html

 主要库与Plugin

Unity Plugin

https://pan.baidu.com/s/1FY2Ge0d9KcVsPOGRehExuQ

主要代码如下:

    public void Connect()
    {
        var cert = Resources.Load("cacert") as TextAsset;

        mqttClient = new MqttClient(ZPropertySocket.ClientIP, ZPropertySocket.ClientPort, false, new X509Certificate(cert.bytes), 
        new RemoteCertificateValidationCallback
            (
                // 测试服务器未设置公钥证书,返回true即跳过检查,直接通过,否则抛出服务器证书无效Error
                (srvPoint, certificate, chain, errors) => true
            ));

        mqttClient.MqttMsgPublishReceived += msgReceived;
        mqttClient.MqttMsgSubscribed += (object sender, MqttMsgSubscribedEventArgs e) =>
        {
        };

        mqttClient.Connect(ZPropertySocket.ClientID, ZPropertySocket.ClientUser, ZPropertySocket.ClientPassword);
    }

其中Client端需要先进行订阅才可以接收到消息,否则收不到Server的发布。Server比较特殊,其不需要订阅也可以接收到Client的发布消息。

    public IObservable<string> Subscribe(string topic)
    {
        var ret = new Subject<string>();
        var k = new KeyValuePair<string, Subject<string>>(topic, ret);
        RecvListeners.Add(k);


        byte[] qos = new byte[1];
        qos[0] = 1;

        string[] msg = new string[1];
        msg[0] = topic;

        mqttClient.Subscribe(msg, qos);

        //mqttClient.Unsubscribe()
        return ret;
    }

Server端

这里使用是MQTTnet

主要使用过程如下:

        private static async Task StartMqttServer_2_7_5()
        {
            if (mqttServer == null)
            {
                // Configure MQTT server.
                var optionsBuilder = new MqttServerOptionsBuilder()
                    .WithConnectionBacklog(100)
                    .WithDefaultEndpointPort(8222)
                    .WithConnectionValidator(ValidatingMqttClients())
                    ;

                // Start a MQTT server.
                mqttServer = new MqttFactory().CreateMqttServer();
                mqttServer.ApplicationMessageReceived += MqttServer_ApplicationMessageReceived;
                mqttServer.ClientConnected += MqttServer_ClientConnected;
                mqttServer.ClientDisconnected += MqttServer_ClientDisconnected;

                Task.Run(async () => { await mqttServer.StartAsync(optionsBuilder.Build()); });
                //mqttServer.StartAsync(optionsBuilder.Build());
                Console.WriteLine("MQTT服务启动成功!");
            }
        }
            string topic = "topic/hello";

            //2.4.0版本的
            //var appMsg = new MqttApplicationMessage(topic, Encoding.UTF8.GetBytes(inputString), MqttQualityOfServiceLevel.AtMostOnce, false);
            //mqttClient.PublishAsync(appMsg);

            var message = new MqttApplicationMessageBuilder()
                .WithTopic(topic)
                .WithPayload(msg)
                .WithAtMostOnceQoS()
                .WithRetainFlag()
                .Build();
            await mqttServer.PublishAsync(message);

有趣的地方,Server端可替Client指定订阅的内容。

        /// <summary>
        /// 替指定的clientID订阅指定的内容
        /// </summary>
        /// <param name="topic"></param>
        private static void Subscribe(string topic)
        {
            List<TopicFilter> topicFilter = new List<TopicFilter>();
            topicFilter.Add(new TopicFilterBuilder()
                .WithTopic(topic)
                .WithAtMostOnceQoS()
                .Build());
            //给"client001"订阅了主题为topicFilter的payload
            mqttServer.SubscribeAsync("client001", topicFilter);
            Console.WriteLine($"Subscribe:[{"client001"}],Topic:{topic}");
        }

另外,其是可以HTTP即ASP.NET一起使用的。这个就可以是一个微服务了。

        public static void Main(string[] args)
        {
            Task.Run(async () => { await ProgramForMQTT.MainTest(); });

            CreateWebHostBuilder(args).Build().Run();


        }

同时也可以使用Dotnet xxx.dll进行启动。

注意问题

对Server端是不需要进行订阅就可以接收到Client的publish的。

这种订阅机制是类似广播,如果想发送给特定的Client,需要每个Client进行单独订阅。

也可以理解每个订阅就是开通了一个频道。

推荐方案是客户端支持多个,可以连接多个Server。Server由于考虑并发性能,目前只支持一个,可以做成单体。

发布了51 篇原创文章 · 获赞 10 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/FeiBin2013/article/details/87274897