您的位置:首页 > 理论基础 > 计算机网络

我的IM - 基础篇[3] - 基于UDP通讯的IM设计[基于XML格式的网络通讯协议 以及 包解析器和包处理器的基础概念] 【转载】

2010-04-29 16:27 609 查看
呵呵 对于我的基础篇[2],我看到有很多朋友很感兴趣,而且有几位朋友提出了很好的意见,呵呵在本次开篇前,我先回应下,

我先讲解下基础的知识,至于朋友们说的东西都会在后面讲到,呵呵别着急,谢谢你们的建议了。

上次我们说到了一个已经被改过多次的协议,我们来回顾下:

  哦,就是这个了,本次的讲解是先要讲述基于XML的通讯协议,然后了解下包解析器和包处理器的基础概念,那么我们开始!

  XML,是可扩展标记语言,自然的,扩展性能很好,大家也许看到了我上面这个红色的自定义协议不好了,为什么呢?

最大的弊端就是,如果我的内容多了,就需要很多分隔符。这个问题也就是很多人在网上发帖问到的,怎么分割命令?

呵呵 那么我继续改造我们的命令,我先直接给出成型的通用通讯协议,然后再给大家介绍(我给出的是最通用的,先不包含包序列号等):

  <Protocol><USERNAME="用户名" PASSWORD="密码" PROTOCOL="0" COMMAND="0" SENDTIME="发送时间" HASHCODE=“唯一码” ISEND="是否结束" ACK="回馈标示" ENCRYPT=“加密标示”></Protocol>

  这个就是更改后的了,很简单,我来带大家了解下,我们使用了XML语言对我们原有的网络自定义命令,进行包装,这样而来,我们的好处很多:

  1. 便于解析(后面会讲到,这个是重点,而且还跟一个重要的概念有关[缓冲池])

  2. 分隔符少,难道不是吗? 呵呵 可能有人又要问我了,如果我的密码之中就有双引号那怎么办?那岂不是拆分的时候要乱套了?

呵呵 ,对于这样的话,我们有2种初步方案进行改造,对于内容部分(被双引号括起来的部分),

  (1) 就是将内容部分中所有双引号进行替换,比如讲双引号替换成 @\*/@

   (2) 就是将内容部分进行2进制转换。

呵呵,总之不管用什么方法,都能够解决以上这点小问题,那么有人问了,你的XML协议只有这个点东西,如果我还要加入用户的等级啊,什么的

岂不是每次我都要用字符串进行拼接,很麻烦?

呵呵 对于上述问题,我的解答是,做一个自己的协议工厂,每个协议的共同部分由协议工厂加工,其余的你只需要给出具体的内容即可。

呵呵 ,我这里给出我的初期小型协议工厂代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ProtocolFactory
{
public class ProtocolFactory
{
/// <summary>
/// 创建协议
/// </summary>
/// <param name="TYPE" type="string">
/// <para>
/// 类别
/// </para>
/// </param>
/// <param name="COMMAND" type="string">
/// <para>
/// 命令类型
/// </para>
/// </param>
/// <param name="PROTOCOL" type="string">
/// <para>
/// 命令协议簇
/// </para>
/// </param>
/// <param name="PackageBody" type="string">
/// <para>
/// 主体数据
/// </para>
/// </param>
/// <param name="ack" type="ProtocolFactory.ProtocolFactory.ACK">
/// <para>
/// 回馈标示
/// </para>
/// </param>
/// <param name="encrypt" type="ProtocolFactory.ProtocolFactory.ENCRYPT">
/// <para>
/// 加密标示
/// </para>
/// </param>
/// <param name="DIC_USERINFO">
/// <para>
/// 自身基础会话码
/// </para>
/// </param>
/// <returns>
/// 返回完整协议
/// </returns>
public static String GetProtocol(String TYPE, int COMMAND, String PROTOCOL, String PackageBody, ACK ack, ENCRYPT encrypt, String SessionCode)
{
String Protocl = "<Protocol><TYPE=\"" + TYPE + "\" ";
Protocl += "COMMAND=\"" + COMMAND + "\" ";
Protocl += "PROTOCOL=\"" + PROTOCOL + "\" ";
Protocl += "SENDTIME=\"" + DateTime.Now.ToShortDateString() + "\" ";
if (SessionCode != null)
{
Protocl += "SESSIONCODE=\"" + SessionCode + "\" ";
}

if (ack == ACK.No)
{
Protocl += "ACK=\"0\" ";
}
else
{
Protocl += "ACK=\"1\" ";
}
if (encrypt == ENCRYPT.No)
{
Protocl += "ENCRYPT=\"0\" ";
}
else
{
Protocl += "ENCRYPT=\"1\" ";
}
Protocl += PackageBody.Replace("\"", "*@^@*");
Protocl += "></Protocol>";
return Protocl;
}

/// <summary>
/// 创建协议
/// </summary>
/// <param name="TYPE" type="string">
/// <para>
/// 类别
/// </para>
/// </param>
/// <param name="COMMAND" type="string">
/// <para>
/// 命令类型
/// </para>
/// </param>
/// <param name="PROTOCOL" type="string">
/// <para>
/// 命令协议簇
/// </para>
/// </param>
/// <param name="PackageBody" type="string">
/// <para>
/// 主体数据
/// </para>
/// </param>
/// <param name="ack" type="ProtocolFactory.ProtocolFactory.ACK">
/// <para>
/// 回馈标示
/// </para>
/// </param>
/// <param name="encrypt" type="ProtocolFactory.ProtocolFactory.ENCRYPT">
/// <para>
/// 加密标示
/// </para>
/// </param>
/// <returns>
/// 返回完整协议
/// </returns>
public static String GetProtocol(String TYPE, int COMMAND, String PROTOCOL, String PackageBody, ACK ack, ENCRYPT encrypt)
{
String Protocl = "<Protocol><TYPE=\"" + TYPE + "\" ";
Protocl += "COMMAND=\"" + COMMAND + "\" ";
Protocl += "PROTOCOL=\"" + PROTOCOL + "\" ";
Protocl += "SENDTIME=\"" + DateTime.Now.ToShortDateString() + "\" ";

if (ack == ACK.No)
{
Protocl += "ACK=\"0\" ";
}
else
{
Protocl += "ACK=\"1\" ";
}
if (encrypt == ENCRYPT.No)
{
Protocl += "ENCRYPT=\"0\" ";
}
else
{
Protocl += "ENCRYPT=\"1\" ";
}
Protocl += PackageBody.Replace("\"", "*@^@*");
Protocl += "></Protocol>";
return Protocl;
}

/// <summary>
/// 回馈标示
/// </summary>
public enum ACK
{
/// <summary>
/// 需要回馈
/// </summary>
Yes,
/// <summary>
/// 不需要回馈
/// </summary>
No
}

/// <summary>
/// 加密标示
/// </summary>
/// <remarks>
///
/// </remarks>
public enum ENCRYPT
{
/// <summary>
/// 需要加密
/// </summary>
Yes,
/// <summary>
/// 不需要加密
/// </summary>
No
}
}
}

对于我的协议工厂,只有一个字段需要解释,那就是"TYPE",对于此字段,我给出的解释就是,为了命令以下级别提供描述。
呵呵 不理解吗? 没关系的。以后会讲解出来,到时候就知道好处咯。

这样的话,每次发送这个由命令工厂制造出来的XML协议就可以了,(如果很大,将会分包,后期讲解,敬请期待)

那么我们现在来了解下 接下来的一些概念,在IM的OOP中,存在着2个类,分别叫"包解析器","包处理器"
这是2个基类,他们提供了所有包解析器和处理器的基础操作。

我们在原来的讲解中,说过,一个IM需要多个协议簇,因此呢,为了每个协议,就要开专门端口进行监听此协议,
那得到了发过来的信息后,如何解析呢?如何处理呢?这就要用到解析器,和处理器了。
  在IM通讯中,包 - 是最小的单位。也就是说包(Package)这个类是所有包的基类,不管你是输入包还是输出包。
不管你是什么协议的输出包,还是什么协议的输入包,都一样(对于包层次结构的详细讲解,下次将会讲述)。
  那么好了,我们就要为每个不同的协议簇产生对于这个协议簇的专门解析器和处理器,这是绝对的,也是必须的。
当我们为一个协议簇构建了单门的解析器和处理器后,我们就要使用它,怎么使用呢?安装它!

  下面是关于我的IM UML图中包解析器和包处理器的部分:
  


那么元接口给出了,大家就要自己些抽象基类,然后按照每个不同的协议派生出自己的解析器和处理器
比如,BASE协议的解析器和处理器呢就是: BaseProtocolParser , BaasePacketListener

呵呵 大家可以看后尝试做下,这样做的好处是什么呢?
那么我门继续看。

下面是我UML 框架图中,关于存放解析器和处理器的2大类



请注意其中的 InstallProcessor()方法 和 InstallParser()方法
呵呵 大家是否开始构思关于这款的详细结构了呢? 安装器所在的类我都已经给出了,大家可以尝试下?

那么下次还是打下伏笔,下次讲解的题目是:我的IM - 基础篇[4] - 输入/输出包的概念

后面的讲解将会非常精彩,敬请关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: