常见游戏后端
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
英雄联盟据说也用这个
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由于考虑并发性能,目前只支持一个,可以做成单体。