3 IM Client与IM Server之间的通讯协议
3.1 数据收发方式与数据结构的设计和定义
3.1.1 数据收发方式的设计
在IM中,所有功能的实现必须依靠客户端与服务端之间的数据通信来完成。在此,需要定义一个协议,让客户端与服务端之间按照定义的协议来进行数据通信,而不是杂乱无章的任意的数据收发。
首先,按照一般惯例,将要发送的数据做成数据包的形式来进行传输,并且分为请求包和应答包。所有的操作都首先由客户终端发送请求包给server端,server对终端的请求进行相应的处理(可能访问数据库)后将结果作为应答包的一部分返回给客户终端,终端通过解析应答包来得到IM server的回应并继续执行相应操作。在进行通讯及运行任何其他的command之前需要进行连接认证。
所有的操作都有“请求——应答”的模式来进行,其过程如图3-1所示。
client请求数据库访问请求的数据serverDB应答
图3-1 请求应答顺序图
3.1.2 通信协议数据包结构定义
由于需要进行传输的数据以及客户端与服务端之间的通信数据的类型是多样化的,必须将种类繁多的数据,以尽可能相同或者相似的结构进行封装,否则,多样化的信息交互和数据传输将给实现功能和代码的编写带来巨大的麻烦和极其烦琐复杂的工作。同时,数据的多样化使得各个数据包的长度将不相一致,甚
至某些数据包的长度大小将是动态可变的,而在SOCKET网络编程中,每一次数据的接收和发送都是需要确定长度的。为此,设计出这样一种方案:将端与端之间一次要发送的数据包分离为两个部分,称为包头和包体,包头中包含有该数据包的相关属性信息,由于只是包含数据包属性而非真正的数据,所以,包头的长度可以是固定不变的。而包体中,则是真正传输的数据所在,数据接收方根据包头中提供的信息得知包体中数据内容的类型,从而针对不同类型的包体做相应的接收和解析工作。图3-2表示出了数据包的大致结构特征。
内容包括:包类型(请求、应答),操作码,
返回码,发送方ID,接收方ID,包体长度等等
包头 包体 其中为相应类型的数据,请求的内容,回应的数据等等,根据数据包的作用和类型不同而不同,长度可变
数据包
图3-2 C/S通信协议数据包结构示意图
3.2 通信协议数据包在实现过程中的定义
3.2.1 数据包包头定义
如图3-2所示,数据包的包头如同人的大脑一般重要,其中包含着该数据包所有的相关属性,能否正确接收变长的包体,解读包中的数据,将其转化为有用的信息,都取决于包体内容的正确解析。在此,将请求包和应答包的包头统一起来,设计出一个一致可行的结构,其实现代码如下:
typedef struct data_packet {
char char char char int32
m_nMajorType; m_strServiceCode; m_strOperationCode; m_nReturnCode; m_nUseless;
}
int32 int32 int32
m_nSendID; m_nRecvID; m_nPacketLength;
其中,每个字段的说明如下表,表后有请求包和返回包的具体说明,如表3-1所示。
表3-1 字段说明表
名称 长度(byte) 说明 区分IM和Mail的消息 IM:0x01 Mail:0x02 为二期开发邮件功能所留 服务名 命令名,具体定义见 返回值 协议扩展 发送者的ID 下面的是特殊ID 0 服务器 接收者ID, 下面的是特殊ID 0 服务器 包体数据长度 m_MajorType 1 m_strServiceCode m_strOperationCode m_nReturnCode m_nUseless m_nSendID 1 1 1 4 4 m_nRecvID 4 m_nPacketLength 总长 4 20 每个终端请求包中:
m_MajorType字段用来区分不同的服务类型,现阶段只使用0x01作为IM的类型,将来可能会增加0x02作为:PushMail的类型。
m_strServiceCode用于区分不同的服务,如认证服务,命令服务等。 m_strOperationCode用于区分同一服务类型中不同的操作,如认证服务中包括登陆请求,断开连接两个操作。设计服务和操作有助于今后的扩展。
m_nReturnCode由应答包使用,请求包将不使用。
m_nPacketLength表示数据包体的长度,以便收取方缺定整个包的长度。 每个服务器应答包中:
m_MajorType,m_nFunctionCode,m_nSourceCode,以及m_strOperationCode
将不使用,只是将请求包的对应值复制到应答包。
m_nReturnCode,供终端判断请求是否执行成功,具体定义见下: #define RT000 0 #define RT001 1 #define RT002 2 #define RT003 3 #define RT004 4
//operate sucessful //deal moudle not found //invalid terminal type //invalid signal name //no data
#define RT099 99 // socket error #define RT100 100 // general error m_nPacketLength同请求包。
服务器每次收到客户请求后,将更新用户当前状态,便于服务器判断用户在线情况。
3.2.2 数据包包体定义
包体的定义实际上则为各类通信的通信数据的定义,由于通信数据种类繁多,在本论文无法将全部定义写出,这里仅通过登陆验证和用户信息获取两个用例的协议数据包定义来阐释数据包具体的定义方式,其他操作相关的数据包包体定义与之类似。
1)用户登陆认证服务
Socket在connect后,发送认证包:m_MajorType为0x01,m_strServiceCode 为0x01, 包体中存放32字节的认证码,前20字节为用户ID,后32字节为MD5后的密码,如果通过校验,则用户可以继续进行接下来的工作;否则,服务器将close掉socket。如果连接后没有发送校验包,超时也将断掉连接。下面将分别介绍在代码实现中如何定义请求包和应答包:
(1)请求包定义 其包头中的属性设置为:
m_MajorType = 0x01; m_nServiceCode = 0x01; m_nOperationCode = 0x01; m_nPacketLength = 52; 包体结构的定义如下: typedef struct data_login {