在制定一个规模比较多大的聊天应用时,往往需要制定部署多个应用服务,其一可以保障服务的可靠性,其二可以增加用户负载量.但制定这样一种应用体系是一件复杂的事情,毕竟同一群体的用户实际上会在不同的服务器接入,这样信息转发和处理就是一件比较麻烦的事情.但通过smartroute的订阅机制这一系列的事情都变得简单.
依据客观情况在设计的时候一般都只是功能优先,对于大规模的应用往往是后期扩展.但是基于集群扩展在设计上就需要做得很多工作作和规划.然而使用smartroute则会变得非常简单,因为并不需要在设计和规划上做多余的工作即可实现跨服务器集群交互.也许你感觉这是不太可能的事情,但以下示例会让你感觉到smartroute的智能之处.
对于以上场景设计需要考虑的事情比较多除了考虑节点和节点的通讯外,还需要考虑用户所登陆的节点,消息如何路由转发和增加节点需要如何切入集群等复杂技情况.而用smartroute不需要安装任何服务和配置即可自动完成,接下来看下如果使用smartroute来解决一些看去都很复杂的工作.
集群服务端实现
如是一开始上面架构规划设计,那肯定是很复杂的工作,那加入smartroute后的设计到底怎样呢?
private static IServer mServer;
static void Main(string[] args)
{
Route.AddLogHandler(new ConsoleLogHandler(LogType.DEBUG | LogType.ERROR | LogType.FATAL | LogType.INFO | LogType.NONE | LogType.WARN));
Route.DefaultNode.Open();
mServer = ServerFactory.CreateTCP();
mServer.Handler = new Program();
mServer.Port = 8012;
mServer.Open();
System.Threading.Thread.Sleep(-1);
}
public void Connect(Beetle.Express.IServer server, Beetle.Express.ChannelConnectEventArgs e)
{
TCPSubscribeHandler tcpsub = new TCPSubscribeHandler();
tcpsub.Channel = e.Channel;
SmartRoute.Protocol.Packet packet = new SmartRoute.Protocol.Packet();
packet.Channel = e.Channel;
packet.Receive = OnMessageReceive;
e.Channel.Package = packet;
Route.Subscribe(e.Channel.ID, tcpsub);
}
public void Disposed(Beetle.Express.IServer server, Beetle.Express.ChannelEventArgs e)
{
Route.UnSubscribe(e.Channel.ID);
UnRegister ureg = new UnRegister();
ureg.IP = e.Channel.EndPoint.ToString();
ureg.Name = e.Channel.Name;
ureg.SendTo(s => s.Mode(ReceiveMode.NotEq), e.Channel.ID);
}
private void OnMessageReceive(object sender, Beetle.Express.PackageReceiveArgs e)
{
IMessage message = (IMessage)e.Message;
switch (message.MessageType)
{
case "Register":
Register reg = message.GetBody<Register>();
e.Channel.Name = reg.Name;
reg.IP = e.Channel.EndPoint.ToString();
reg.SendTo(s => s.Mode(ReceiveMode.All), e.Channel.ID);
break;
case "Speak":
Speak speak = message.GetBody<Speak>();
speak.User = new Register();
speak.User.Name = e.Channel.Name;
speak.User.IP = e.Channel.EndPoint.ToString();
speak.SendTo(s => s.Mode(ReceiveMode.NotEq), e.Channel.ID);
break;
}
}
你没有看错,以上代码就是一个基于集群的简单聊天服务网关,看上去是不是比编写一个普通网络程序的来得更简单多.接下来讲解一下主要代码的作用.
注册订阅
当网关接受到接入的时候会向节点注册一个订阅Route.Subscribe(e.Channel.ID, tcpsub);,而订阅的ID则连接在当前服务的唯一标识,而订阅实现是一个TCP连接订阅.
取消订阅
当网关接受到断开的时候则取消订阅 Route.UnSubscribe(e.Channel.ID);
发送消息
而当网关接收到消息的情况则把消息投递出去,reg.SendTo(s => s.Mode(ReceiveMode.All), e.Channel.ID)是投递给所有订阅, speak.SendTo(s => s.Mode(ReceiveMode.NotEq), e.Channel.ID)则投递给非当前Channel.ID的所有订阅
智能组建节点集群
如果这个服在当前局域网内只运行一个实例,那它紧紧是一个普通的服务端,但如果节点发现网内还有其他节点在运行的情况下则会去发现对方并组建成通讯集群.当组建集群后每个节点的订阅信息都会同步到不同节点下,每个节点都是相互直连不存在中心服务.当一个节点接收一个消息投递的时候会找相应的订阅,如果是本机订阅则会直接调用订阅;如果是订阅在其他节点则把消息投递到相应的节点,由相应的节点调用订阅.
单节点动行效果
多节点运行效果
一旦节点发现网内有其它节点就会发现组建集群并同步订阅,一集群组建完成后就可以通过节点进行信息交互.
总结
实际上一个聊天服务的功能并不这么简单,往往具备有大厅,群组等等.其实使用smartrote处理这些信息转发则是非常简单的事情.可以针对大厅,群组制定订阅服务节点;然后消息发送到相关订阅,然后再由这些服务查找出具体的订阅用户然后分发即可.所以smartrote的订阅看上去是很简的功能,实现上可以实现很多意想不到的功能,如FTP,HTTP和MQ等等订阅的实现并注册到smartroute中统一集成分发.