我的IM - 基础篇[2] - 基于UDP通讯的IM设计[开篇] 【转载】
Posted on 2010-04-29 16:26 Happy Coding 阅读(828) 评论(0) 编辑 收藏 举报呵呵, 在上一篇文章中的末尾,我粘贴了来自我的框架部分截图,相信大家也很感兴趣,而且我也会毫不保密的继续为大家介绍精彩的IM技术讲解。
这篇文章由我来讲解下基于IM的UDP通讯协议设计(开篇 - 1)
大家都用过QQ吧?经常用吗?知道QQ的原理吗?会“拆”QQ吗?呵呵,作为一个IM研究人员,就要经常的对现有市场产品进行剖析。
QQ,是基于UDP通讯协议的,这个毋庸置疑,我来剖析下QQ(以QQ2009为例):
当大家打开QQ后,他会自动开启UDP端口若干(4000~6000)2个分段依次累加,当时我就在想,为什么他开那么多端口呢?有必要开那么多端口吗?
呵呵 那么好,前言,现在开始本次讲解。
现在的即时通讯软件中,大部分采用了UDP协议,原因有以下几个:
1. UDP协议不用一直保存用户SOCKET,也就是断开式的,这样节省资源
2. 为了服务器转发各种消息得到了便利
3. 为了更好的减少异常的出现(比如用TCP/IP时的异常断开?)
我在项目中也是采用的UDP通讯协议,大体的框架图可以看上一篇的,那么开端口,为什么像QQ那样开那么多端口呢?
呵呵 这里我也给大家解答下,作为IM编写者,要时刻保持一种概念:一个QQ是可以支持不同协议簇的,而每个协议簇又包括了该协议簇的各种命令
这就是为什么QQ会开有多个UDP端口,因为为了支持不同的协议!!
我想看这篇文章的人,很多人在写C/S模式软件的时候是不是仅仅拥有1个协议呢?
呵呵 还不理解?我打个比方,你的IM 注册,登陆用户,获取用户信息,聊天。。处理分组操作,处理好友操作是不是都是开1个UDP端口呢?
如果不是,那是因为什么开那么多呢?
然后大家用这一个UDP端口接收后,会有“命令树”(我们的俗称),说白了无非就是下面的形式:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
那么,这样就很清晰了,为了已更好的方式优化IM程序,我们会为每个协议簇单门指定端口进行监听。
这样呢,就是4个UDP了对不?
好了,那么现在就需要继续上次讲解的知识了,我们使用具有包含关系的PortListener 和MessageListener成功的监听了4个UDP端口,
什么? 您不会还要用刚才的命令树来判断命令吧?????
呵呵 让我们开拓思路下,什么方法能耦合度低,而且易维护,简单,方便呢?
我这里提出来我的项目经验,呵呵 直接给出大家对于这样很伤脑筋的正确解决途径。
我先来大概的讲下我们的通讯,作为UDP通讯,我们会有2个很大的枚举,一个叫做"IN_NETWORK_COMMAND"另一个叫做
"OUT_NETWORK_COMMAND",这样的分工,大家待会儿就会明白好处了。
那么好,"IN_NETWORK_COMMAND" 主要用来保存我当前接受到的包协议命令
"OUT_NETWORK_COMMAND"主要用来保存我们要发送的包协议命令
来看下我项目中这2个枚举(包含于我的UML通讯框架中):
不知道,大家可否看出其中的秘密? 呵呵 细心的人一定看到了,我的,"IN_NETWORK_COMMAND" 和"OUT_NETWORK_COMMAND"
都是一一对应的,这就是解决方案了!
那么好,接下来继续,原来我们定义的协议最早是什么样子呢?
我给出这里大部分人的协议(比如登录):Login$用户名{**}密码{**}{|*End*|}
这个就是我所见过的很多人的关于用户登陆的自定义协议,对方还很有根据:跟我说“我接收到这样的命令后,首先呢,会看看是否存在{|*End*|}
,如果存在呢,那当然这条命令就是完整的了,然后呢用{**}分割,就能得到用户名和密码啦!”
呵呵,那么好,关于这位朋友的自定义协议命令,我不想多说什么,因为我会在下次讲解中来讲解项目中正确的解决方案,这次实例就拿他的这个协议作比喻:
我们如何来区分当前协议所属的协议簇呢? 呵呵 还记得刚才我们定义的协议簇枚举吗?enum类型可以被转换为int!
这就够了,那么在原有的基础上我们可以加上:
Login$用户名{**}密码{**}0 (<--这个0代表协议簇编号,是由枚举强转的){**}{|*End*|}
好了,我们在自定义的命令中已经插入了这条命令所属的协议编号,我们继续改,不用Login$头作为命令自定义头了,我们还用刚才的方法将你想要的命令编号
从命令枚举中,强转为int
这样的话,这个自定义命令变为:
用户名{**}密码{**}0 (<--这个0代表协议簇编号,是由枚举强转的){**}0 (<--这个0代表命令编号,是由枚举强转的){**}{|*End*|}
呵呵,这次看起来是不是舒服多了? 大多数可能认为,这样有什么好处呢?到了服务端不是照样要拆分吗?
呵呵 这样的好处多多,会由下次课来为大家讲解为什么这样的采用命令编号效果会好,那么我提前告诉大家下。
下次讲解的题目叫做"我的IM - 基础篇[3] - 基于UDP通讯的IM设计[基于XML格式的网络通讯协议]"
呵呵这里埋下伏笔,有兴趣的朋友可以想象有什么具体好处呢?
好了,我们回顾下本次讲解的内容:
1. 提出了不正确命令树写法
2. 抛出了大部分人自定义的通讯协议命令,并且更正了部分参数
3. 解答了为什么会开多个UDP端口
4. 提出了协议簇枚举概念
5. 提出了自定义协议命令(IN/OUT)枚举初步方案
呵呵 对于本次讲解,您还满意吗? 下面的讲解将会更加精彩!!!