本文重点在于对飞鸽协议原理及部分网络知识进行普及性的介绍,尽量避免用专业的术语吓跑非计算机专业朋友,如果有介绍的不合理的地方,也欢迎高手出来拍砖。
飞鸽概述
飞鹆传书作为免费的开源软件,在全世界各国享有声誉,其原作者是H.Shirouzu,其windows平台的C++源码下载地址为http://www.azhi.net/IPMsg/ipmsg206src.zip。除windows平台的实现以外,还存在大量其它平台的飞鸽实现,如Mac,Linux,甚至还存在平台无关的Java版本。
本人开发的飞鸽传书,实际上是在M8平台上实现了该协议子集。从而能够实现局域网内用户发现,接收PC版飞鸽传入的消息、文件、文件夹。
本人实现的飞鸽,可参考如下两个帖子:
1 http://bbs.meizu.com/thread-791903-1-1.html
2 http://bbs.meizu.com/thread-814371-1-1.html
飞鸽能够实现这种异构平台之间的通信,在于它的源码和协议是开放的,只要遵守相应的传输协议,就可以实现通信。
这里要强调一个概念,网络传输类应用程序,协议是重中之重。那么,协议到底是什么呢?协议可以让运行于两个不同平台的程序之间做到“心有灵犀一点通”,也有点像黑帮内部的切口:A说了天王盖地虎,B就要说宝塔镇荷妖。
有点扯远了,计算机网络应用中的协议,是要解决一些很实际的问题,比如,以飞鸽为例,计算机A向计算机B可以发消息,也可以传文件。都是通过网络传递数据,B如何能知道,这些数据中什么是消息,什么是文件呢?这就需要设计通信协议,通过一些命令字描述当前或即将传送的数据是什么内容。从而使得接收方,能够正确理解发送方发出的内容。
网络基础,TCP/IP协议简介
TCP/IP是很复杂的,要介绍这个已经远远超出我的能力范围,但我仍然可以对它的上层使用做简单的介绍。
前面我们花了大量的篇幅加口水强调协议在网络应用中的重要性。那所谓的飞鸽协议,与我们平时常常听到的TCP/IP有什么区别和联系呢?这个问题问的好(我自己问的)!
计算机网络的设计有着非常多的成功的可取之处,其中之一就是分层。按照问题所在的领域,将问层划分到不同的层中去解决(读者可自行参考OSI的七层模型以及TCP/IP的五层模型)。TCP/IP协议在传输层提供的UDP和TCP传输协议,成为了我们构建应用层软件(如,聊天,下载,邮件,http等等)的基础。
TCP传输协议规定了通信双方需要一个“连接-接受”这样的连接确认过程,既所谓的三次握手过程。一但连接建立成功,双方可以通过该连接,进行可靠的数据通信。
UDP传输协议不需要双方进行连接,发送方只需要指定接收方的地址和端口,若接收方此时正在该端口等待接收,那接收方就有可能(网络质量不好的话,可能会丢,不过局域网里通常不会发生这样的情况)收到消息。
除此之外,还有一个重要的概念是广播,将数据包发送到广播地址(用UDP协议发送),则该网段的所有用户,都可以收到这条数据。
飞鸽协议分析
飞鸽的协议也属于应用层协议,它描述了飞鸽程序通信时的语法和语义。
其语法定义如下(所有的命令字,都必需符合这样的格式要求):
Ver(1): PacketNo:SenderName:SenderHost:CommandNo:AdditionalSection
每部分分别对应为:版本号(现在是1):数据包编号:发送主机:命令:附加数据
其中:
数据包编号,一般是取毫秒数。利用这个数据,可以唯一的区别每个数据包;
SenderName指的是发送者的昵称(m8飞鸽被我统一的写死为m8,现在知道怎么定制了吧?);
发送主机,指的是发送主机的主机名;
命令,指的是飞鸽协议中定义的一系列命令,具体见下文;
附加数据,指的是对应不同的具体命令,需要提供的数据,具体见下文。
上面介绍了数据包的语法,即格式,这些命令都是通过UDP协议向其它主机发送的。
接下来列出协议的命令,包括命令字及附加选项:
1) Command functions (Low 8 bits from command number 32 bits)
IPMSG_NOOPERATION No Operation
IPMSG_BR_ENTRY Entry to service (Start-up with a Broadcast command)
IPMSG_BR_EXIT Exit from service (End with a Broadcast command)
IPMSG_ANSENTRY Notify a new entry
IPMSG_BR_ABSENCE Change absence mode
IPMSG_BR_ISGETLIST Search valid sending host members
IPMSG_OKGETLIST Host list sending notice
IPMSG_GETLIST Host list sending request
IPMSG_ANSLIST Host list sending
IPMSG_SENDMSG Message transmission
IPMSG_RECVMSG Message receiving check
IPMSG_READMSG Message open notice
IPMSG_DELMSG Message discarded notice
IPMSG_ANSREADMSG Message open confirmation notice(added from version-8)
IPMSG_GETFILEDATA File Transfer request by TCP
IPMSG_RELEASEFILES Discard attachment file
IPMSG_GETDIRFILES Attachment hierarchical file request
IPMSG_GETINFO Get IPMSG version info.
IPMSG_SENDINFO Send IPMSG version info.
IPMSG_GETABSENCEINFO Get absence sentence
IPMSG_SENDABSENCEINFO Send absence sentence
IPMSG_GETPUBKEY RSA Public Key Acquisition
IPMSG_ANSPUBKEY RSA Public Key Response
2) Option flag (High 24 bits from command number 32 bits)
IPMSG_ABSENCEOPT Absence mode(Member recognition command)
IPMSG_SERVEROPT Server(Reserved)
IPMSG_DIALUPOPT Send individual member recognition command
IPMSG_SENDCHECKOPT Transmission check
IPMSG_SECRETOPT Sealed message
IPMSG_READCHECKOPT Sealed message check(added from ver8)
IPMSG_PASSWORDOPT Lock
IPMSG_BROADCASTOPT Broadcast message
IPMSG_MULTICASTOPT Multi-cast(Multiple casts selection)
IPMSG_NEWMUTIOPT New version multi-cast(reserved)
IPMSG_AUTORETOPT Automatic response(Ping-pong protection)
IPMSG_NOLOGOPT No log files
IPMSG_NOADDLISTOPT Notice to the members outside of BR_ENTRY
IPMSG_FILEATTACHOPT File attachment
IPMSG_ENCRYPTOPT Code
IPMSG_NOPOPUPOPT (No longer valid)
IPMSG_RETRYOPT Re-send flag(Use when acquiring HOSTLIST)
3) Extended code flag (hex format combination)
IPMSG_RSA_512
IPMSG_RSA_1024
IPMSG_RSA_2048
IPMSG_RC2_40
IPMSG_RC2_128
IPMSG_RC2_256
IPMSG_BLOWFISH_128
IPMSG_BLOWFISH_256
IPMSG_SIGN_MD5
4) Extended files for attachment (fileattr low 8 bits)
IPMSG_FILE_REGULAR
IPMSG_FILE_DIR
IPMSG_FILE_RETPARENT
IPMSG_FILE_SYMLINK
IPMSG_FILE_CDEV
IPMSG_FILE_BDEV
IPMSG_FILE_FIFO
IPMSG_FILE_RESFORK
5) Attachment file extended attribute(fileattr high 24 bits)
IPMSG_FILE_RONLYOPT
IPMSG_FILE_HIDDENOPT
IPMSG_FILE_EXHIDDENOPT
IPMSG_FILE_ARCHIVEOPT
IPMSG_FILE_SYSTEMOPT
6) Extended file attribute for attachment file
IPMSG_FILE_UID
IPMSG_FILE_USERNAME
IPMSG_FILE_GID
IPMSG_FILE_GROUPNAME
IPMSG_FILE_PERM
IPMSG_FILE_MAJORNO
IPMSG_FILE_MINORNO
IPMSG_FILE_CTIME
IPMSG_FILE_MTIME
IPMSG_FILE_ATIME
IPMSG_FILE_CREATETIME
IPMSG_FILE_CREATOR
IPMSG_FILE_FILETYPE
IPMSG_FILE_FINDERINFO
IPMSG_FILE_ACL
IPMSG_FILE_ALIASFNAME
IPMSG_FILE_UNICODEFNAME
基于上面介绍的内容,我们可以判断:
1:100:shirouzu:jupiter:32:Hello 表示 shirouzu用户发送了 Hello 这条消息(32对应为IPMSG_SEND_MSG这个命令,具体需要看源码中的宏定义)。
==========================================
以下内容未完待续,困了,明天再写
好,接下来我们进入具体场景的分析:
登录/离线通知
登录过程需要实现向局域网内的用户广播,告诉他们,“我来也!”。收到这条消息的用户则立即回复,“知道了,我在这里”,同时将新登录的用户加入到用户列表中。发送方也可根据收到的回复信息,了解到当前网络中,都有哪些已经登录了的用户。
具体的数据包如下:
登录方(要发送到广播地址,如255.255.255.255):
1:XXX:m8:<主机名称>:IPMSG_BR_ENTRY:
接收方回复(发送到发送方的IP地址):
1:XXX:<接收方主机名>:IPMSG_ANSENTRY:
相应的,用户离线时,应向广播地址发送,“我去也!”,收到这条消息的用户,需要将发送方从自己的用户列表中移除,并且不需要回复。
具体的数据包如下:
即将离线用户:
1:XXX:m8:<主机名称>:IPMSG_BR_EXIT:
发送/接收消息
发送消息是飞鸽协议中最重要的部分,通过和一些命令选项,可以实现复杂的功能:
最基本的情况下,发送方通过 IPMSG_SEND_MSG 命令,可以将消息发送到接收方
1:12345:m8:<主机名称>:IPMSG_SEND_MSG:你好,飞鸽
使用命令时,“附加数据”开使发挥作用了它里面包含了要发送的消息。
通常情况下,由于UDP的不可靠性,还需要为 IPMSG_SEND_MSG 命令设定 IPMSG_SENDCHECKOPT选项,也就是要求接收方回复回执信息。
1:12345:m8:<主机名称>:IPMSG_SEND_MSG|IPMSG_SENDCHECKOPT:你好,飞鸽
接收方收到IPMSG_SEND_MSG时,如果遇到IPMSG_SENDCHECKOPT选项,就要立即回复如下信息:
1:XXX:<用户名>:<主机名>:IPMSG_RECVMSG:12345
IPMSG_RECVMSG命令通过附加数据段中的数据(12345),告诉发送方,我收到了你的编号为12345的消息包。
除了上面介绍的IPMSG_SENDCHECKOPT选项,飞鸽还支持加密得选项,现有的m8版本没有实现该功能,所以暂不对这一块进行介绍。
发送/接收文件
文件的传输,要稍微复杂一些,它是通过 IPMSG_SEND_MSG 命令与 IPMSG_FILEATTACHOPT选项的组合,通知接收方“现在有文件要发给你了”,同时要将一些描述文件属性的数据(如文件名、大小、创建时间、类别属性如文件夹),发送给接收方,具体格式如下:
file1ID:filename:size:mtime:fileattr[:extend-attr=val1[,val2...][:extend-attr2=...]]:\a:file2ID...
这里需要注意的有几点,第一,一条文件传送命令,可以携带多条文件信息;第二,多个文件信息之前,要用\a分割;第三,size, mtime和fileattr 是用十六进制数描述的);第四,如果文件名中包含“:”,则需要将其转义为“::”。
相应的,接收方收到文件传送命令后,首先需要从文件属性的数据中解析出要接收的文件的属性。然后向发送方相同的端口进行TCP连接,连接成功后,通过TCP通道向发送方发送IPMSG_GETFILEDATA命令用于接收文件或发送IPMSG_GETDIRFILES命令,用于接收文件夹。具体接收文件的命令如下:
1:XXX:m8:<主机名>:IPMSG_GETFILEDATA:packetID:fileID : offset
这条命令通过packetID,让发送方明白对方请求的文件是源于哪个命令包;通过fileId让发送方确定要发哪个文件;通过offset;让发送方明白要从哪个字节开始发送。
发送方的TCP通道收到上面的命令,就会发送对方请求的文件;而接收方将收到的数据保存到磁盘上即可。