飞信2010分析 – 成功登录之后

2010年4月12日 | 分类: 飞信哪些事儿 | 标签:

文章更新晚了,请大家见谅,上周的事情比较多,呵呵~

标题里面的成功登录之后指的是SIPC验证成功之后。也就是说登录成功是指在完成第一步获取系统配置信息,SSI登录成功,SIPC验证成功之后才能算登录成功。

在SIPC验证成功之后,服务器会返回很多信息,登录记录,个人信息,好友分组,好友列表,个人配置等,这些信息在2008的协议里面都是逐个发起请求来获取的,现在2010的协议登录成功就直接把这些所有的数据都返回来了,这个改进还不错,减少了很多操作。如果没有返回某一类的信息,表明本地存储的信息版本和服务器一致,就直接读取缓存,如果不做缓存,也就是说本地版本总是0,服务器也会总是返回数据。

这里再详细的的说下其中的好友列表,这是其中的一个好友节点:

<b i="987654321" u="sip:123456789@fetion.com.cn;p=1234" n="阿呆" l="5" f="0" r="1" o="0" p="identity=1;phone=1;email=1;birthday=1;presence=1;"/>

为了便于分析,这里转为完整的拼写如下:

<buddy user-id="987654321" uri="sip:123456789@fetion.com.cn;p=1234" local-name="阿呆" buddy-lists="5" feike-read-version="0" relation-status="1" online-notify="0" permission="identity=1;phone=1;email=1;birthday=1;presence=1;"/>

简单的说下简写代表的含义:
b = buddy   : 好友,飞信好友分成两种,飞信好友和手机好友,顾名思义,飞信好友就是开通了飞信的好友,其中的uri的格式是sip:123456789@fetion.com.cn;p=1234;sip和@符号之间的就是飞信号,登录的时候可以用这个飞信号登录。p=1234我也不知道什么含义。 手机好友指的是没有开通飞信的好友,其uri的格式tel:159xxxxxxxxx,后面是手机号。没有开通飞信的好友没有昵称,Email等好友信息。
i = user-id : 用户编号。注意这个不是飞信号。所谓的用户编号指的是移动所有的用户如果使用飞信的话就会自动分配一个用户编号。这个编号无论用户开通还是没有开通飞信这个编号都存在而且不会改变。飞信的URI可能会改变,比如用户原来没有开通飞信现在开通了飞信URI就会变。
u = uri     : URI。用户标志,类似于URL。很重要,飞信里面的操作都是基于URI来识别用户的。如发送消息说明给那个用户发送就是使用URI。实在是搞不懂为啥飞信使用两个唯一的字段来标志用户。
n = local-name  : 用户设置的本地昵称。这个是用户设置,不是好友的昵称,如果用户没有设置本地昵称,就为空,如果要显示好友昵称,就需要发起获取好友详细信息请求来获取昵称。
l = buddy-lists : 好友所属的分组编号列表,多个列表以;隔开。飞信做得挺有意思的,一个好友可以属于多个分组,实现起来也麻烦,这个完全是个错误的需求。。
f = feike-read-version : 这个是判断飞客是否有更新的
r = relation-status : 好友和用户的关系。有三个值 1:添加对方后对方没有回复 2:对方同意了你添加好友的请求 3:对方拒绝了你添加好友的请求
o = online-notify : 这个含义未知。。
p = permission : 该好友对用户设置的权限。
飞信的权限有五种:
identity=1: 向对方公开我手机号码和姓名
birthday=1: 向对方公开我的生日和年龄
phone   =1: 向对方公开我的电话号码 (不是手机。。飞信为啥这里还搞个电话号码。。)
email   =1: 向对方公开我的电子邮件
business=1: 向对方公开我的商务信息
presence=1: 向对方公开我的在线的状态信息,如果不公开,默认为离线状态

当相应的值为1的时候,就表明向对方公开相应的信息。飞信的权限设置的很复杂很乱,很多都是没有必要的。当对方权限设置为0的时候,获取对方的信息的时候就会是空值。真搞不懂飞信把权限做的这么复杂。

chat-friend这个什么含义还不清楚,black-list里面的好友列表不能看见用户的在线状态,也不能向用户发送信息。

上篇文章最后说登录成功好友的状态信息没有发送过来,这就需要做个请求,订阅好友的在线状态。

为啥要定义好友的状态呢?订阅的目的就是当好友状态改变的时候,能及时发送给客户端。其实这里的状态包含了很多的信息,比如用户新更改了昵称,个性签名,更换了头像,或者用户登录,下线了等等,都是通过状态改变发送给客户端的。如果不订阅,服务器是不会主动的发送状态改变信息到客户端的。

SUB fetion.com.cn SIP-C/4.0
F: 123456789
I: 10
Q: 1 SUB
N: PresenceV4
L: 87

<args><subscription self="v4default;mail-count" buddy="v4default" version="0" /></args>
----
SIP-C/4.0 200 OK
I: 10
Q: 1 SUB

这在飞信里面都是固定的值。只是最后一个version是变化的,含义是最后更新好友信息的版本号。但可以直接固定为0。

返回没有数据,那好友的在线状态服务器是怎么返回的呢?因为飞信SIPC连接是基于TCP,数据可以双向发送,飞信服务器在接收到用户订阅的请求之后,会通过一个通知发送给客户端。

这里的通知可以这样理解:通常是客户端发起一个请求,服务器响应并发送一个回复,但通知不一样,是服务器主动发起的,消息格式和请求相似。服务器发出的有些通知需要客户端发送回复,如M,I等,但有些不需要回复,如BN通知。用户的在线状态就是通过一个不需要回复的BN通知来主动的发送给客户端的。

这是服务器发回的一个BN通知,其中的N(Event)的值为PrensenceV4表明是状态通知。

BN 123456789 SIP-C/4.0
N: PresenceV4
I: 1
L: 360
Q: 8 BN

<events><event type="PresenceChanged"><contacts><c id="1111111"><p v="320594199" sid="123456789" su="sip:123456789@fetion.com.cn;p=1234" m="13xxxxxxxx" c="CMCC" cs="0" s="1" l="8" svc="" n="神啊" i="我怎么选这么一条山高水长的路.." p="-207750749" sms="0.0:0:0" sp="0" sh="0"/><pr di="PCCL030655017606" b="400" d="" dt="PC" dc="1ff"/></c></contacts></c></contacts></event></events>

可以看出格式和请求基本相同,但头部不一样,请求的头部是METHOD fetion.com.cn SIP-C/4.0,第二部分是一个域名。而通知的格式是METHOD 123456789 SIP-C/4.0,第二部分是飞信号,没有按照标准的SIP协议处理,这点要注意。由于是简写,为了便于分析,这里转为完整的拼写。如下

<events><event type="PresenceChanged"><contacts><contact user-id="1111111"><personal version="320594199" sid="123456789" su="sip:123456789@fetion.com.cn;p=1234" mobile="13xxxxxxxx" carrier="CMCC" carrier-status="0" provision="1" score-level="8" svc="" nickname="神啊" impresa="我怎么选这么一条山高水长的路.." portrait="-207750749" sms="0.0:0:0" feike-version="0" fetion-show="0"/><presence device-id="PCCL030655017606" basic="400" desc="" device-type="PC" device-caps="1ff"/></contact></contacts></event></events>

看起来很简单,一看就懂。简单说一下其中比较重要的。

personal 节点中,返回了好友的基本信息
version: 好友信息版本,上面说的订阅通知的version的值就是上次登录最后一次获取到好友状态通知中的好友信息的版本。有点绕口。。
carrier: 这个中文还不知道翻译为啥,可以理解为飞信用户注册的网关,飞信定义了很多的carrier,不同的carrier可以进行的操作有所不同,这个我会写文章详细分析的。
provision,svc: 很遗憾,这俩个不知道啥含义。。
nickename: 好友设置的昵称
impresa: 好友的个性签名
portrait: 好友头像编号,如何获取请见以后的文章。
sms: 这个很重要。在飞信的客户端里显示短线在线和离线的状态就是通过这个来判断的。
presence节点中,返回了好友的状态信息
basic:好友的状态,0:离线 100:离开 400:在线 600:忙碌
desc:用户可以自定义状态,这个是对这个状态的回复
device-caps:好友所使用客户端的功能掩码,见以后的文章对carrier的分析。

飞信有个状态叫短线在线,这个状态在basic里是没有的。如何判断是短信在线状态呢?

其实basic为0有两种情况,好友的确不在线,或者好友隐身。当basic为0时,判断用户是否为离线状态就需要使用到personal节点中的sms属性。

这个属性挺有意思的,代表了一个时间长度。其格式是这样的:天数.小时数:分钟数:秒数。如 1.2:14:51 代表的就是1天2小时14分钟51秒。

sms属性的含义就是从现在算起,多少时间内不用手机短信接收飞信信息。如果好友当前离线,并且这个时间为0的时候,就可以发送手机短信给好友,这个状态就是短信在线状态。如果这个时间不为0,表明当前用户不允许接受飞信往手机发送短信,就是离线状态。

通常用户设置多少时间内不通过手机短信接收信息也是通过设置sms属性来完成的,如果想要永远不用短信接收飞信信息就可以把这个时间长度设置为365天。

这个Presence通知服务器会发很多,并且一个Presence通知可能包含了多个好友的状态通知。

在订阅用户状态之后,就可以进行发消息,添加好友操作了。

但飞信仍需要保持登录状态,就是常说的心跳包,飞信没隔一段时间就需要发送心跳包,向服务器表明我还活着。如果在指定的时间内,服务器没有接收到心跳包,就会关闭连接。

发送心跳包很简单

R fetion.com.cn SIP-C/4.0
F: 123456789
I: 1
Q: 12 R
N: KeepAlive
L: 97

<args><credentials domains="fetion.com.cn;m161.com.cn;www.ikuwa.cn;games.fetion.com.cn" /></args>
------
SIP-C/4.0 200 OK
I: 1
Q: 12 R
X: 600
L: 1143

<results><credentials kernel="q0RO8z5tnzPG/vQzXomdxOQrIQj0ueJ9qzSO0p1H1huRPCZDU75TvvzM1S1ZjCNHXdJEBWshS18atsuvz44Sdb6IBfESHblXKO02irDfctyXqBzAFEZTMefSWdnsjYWTT4ZoKOsvGPadIy1lDIH3kFwNdXyT29QVoEmZLv7dyysGVgTVYoKYRBROPb1sI7bX"><credential domain="fetion.com.cn" c="Tn7rZeHrAi1LUwTBS76rhs8wHhehgDlEaT238LmOR+DP7YGqq6y4u0FHs49W2VfjyzG2Vfd4tB2fRtBGbrQgHM6Mvm46RE8uj5dUAIkDRrnH08N/wAIOHT7ZoXmKnFehUv1TXOcOPgSEGtk2UgNpLkKWLm240yMgSRB9h0pK2sN1RZ5n24espOEZjXLKqOSC"/><credential domain="m161.com.cn" c="FmN1TSh5u2L8IMiTQEYFU9P0rOcLDwNikvgIOc5CMWvTQoMqJVpuEOXIU/EeFhUhpZsVSIVnV7j3xXaIwAoLWMdQsgVN8o9rGgrln7DnXY5wHmhynDYLPvMJkre48cNQUg+O9KMYDNundunclLFQT73YRRwp2ir6MHzInRrtGCI="/><credential domain="www.ikuwa.cn" c="fnMks5H+NBOPBBDCfnnU32m8P7lXW3d6+A0oWOi2fKBDMiJNZTywlJgv11wcFnBQ0t+s3s9PhDSL0joaBsjt4pFMP5gFE9RtsdPZf8TRWp+/mjExDIOuc59JlzFM6ReLYZuORN5RyEnEdGjv48w+oAwNrzv9y6mDmHTjXY+fpUM="/><credential domain="games.fetion.com.cn" c="oKTnVNzRazcKbDJIZsRrjBbVEavcd7AOir16gD54fYqTHOjsQm4l7wQLXelImM1IRocvXm+QN8CKmhxU9+kuiWohgN3GHtZdulxipD1ne0KUqlklEm5Su1CVE13lO+Ym0IAW0mJFLZDsXwj/RmiFKfApcEsaUqcyq8x2/AZnkT6pFm8BIFArBkhBfhV0zUIb"/></credentials></results>

其中请求中I固定为1,Q中序号逐次递增就成了。返回了很多的credential,这么多的credential干啥用的,暂时还不清楚,可能和HTTP的应用程序有关,比如获取用户头像,共享图片等。暂时放下,以后分析这个了。。

注意返回的头部中的X,其实就是Expired的意思,是个时间单位秒,就是说这个保持登录在多少秒过期,客户端必须在这个时间之前发送下一次保持在线的请求,否则服务器就会断开连接。

登录至此分析完毕,下文分析发送短信部分,敬请关注。

  1. 2010年4月12日20:35

    高手,学习 嘿嘿

    [回复]

  2. 江郎才进
    2010年4月20日10:42

    期待大牛更新博客呀~~

    [回复]

  3. 2010年4月21日16:39

    请教下,2010协议中,取消了GetContactsInfo了吗?获取多个好友的详细信息一定要先订阅好友的在线状态?之前2008版有GetContactsInfo能获取多个好友的昵称的,2010中有类似的吗?

    [回复]

  4. 2010年4月21日17:34

    @Terry
    刚测试了一下 这个方法像不行了 只能一次请求一个好友的详细信息

    S fetion.com.cn SIP-C/4.0
    F: 123456789
    I: 4
    Q: 1 S
    N: GetContactInfoV4
    L: 100
    
    
    -----------------------------------------------------
    SIP-C/4.0 400 Bad Request
    I: 4
    Q: 1 S
    

    [回复]

  5. rain
    2010年5月7日23:16

    4月6号的代码发不了消息。
    protected void ensureOpened()
    {
    if(this.state == DialogState.CLOSED) {
    throw new IllegalStateException(”Dialog is closed.”);
    }else if(this.state == DialogState.OPENNING) {
    throw new IllegalStateException(”Dialog is openning.”);
    }else if(this.state == DialogState.CREATED){
    throw new IllegalStateException(”Dialog just created.”);
    }else if(this.state == DialogState.FAILED) {
    throw new IllegalStateException(”Dialog is failed to open.”);
    }
    }

    [回复]

    solosky 回复:

    这个错误我也更新了。

    [回复]

  6. rain
    2010年5月7日23:18

    ContactNotifyHandler 类有错。少了两行。

    [回复]

  7. 2010年5月7日23:35

    @rain

    你好!感谢你的支持!那个错误是我昨天误操作造成的,给你造成的麻烦感到抱歉。
    我已经修正了代码并提交到代码库了,请检出最新版本再试,谢谢~

    [回复]

  8. rain
    2010年5月7日23:40

    java.lang.IllegalStateException: Dialog just created.
    at net.solosky.maplefetion.client.dialog.Dialog.ensureOpened(Dialog.java:129)
    at net.solosky.maplefetion.client.dialog.BasicChatDialog.sendChatMessage(BasicChatDialog.java:82)
    at net.solosky.maplefetion.FetionDemo.send(FetionDemo.java:801)
    at net.solosky.maplefetion.FetionDemo.to(FetionDemo.java:367)
    at net.solosky.maplefetion.FetionDemo.dispatch(FetionDemo.java:983)
    at net.solosky.maplefetion.FetionDemo.mainloop(FetionDemo.java:947)
    at net.solosky.maplefetion.FetionDemo$18.run(FetionDemo.java:923)
    at java.lang.Thread.run(Unknown Source)

    [回复]

    solosky 回复:

    请问你的问题解决了吗 ?如果没有解决,请给我发邮件,我会尽力解答的,谢谢~
    solosky772@qq.com

    [回复]

  9. rain
    2010年5月8日00:01

    感谢你的回答,新加了demo,不错,帮助快速入门。

    [回复]

    solosky 回复:

    @rain,
    Demo是早就改写了,现在抽出点时间写个Demo,再写个教程,就可以发布新版本了,呵呵··

    [回复]

  10. rain
    2010年5月8日00:03

    发在线消息时还是出错。
    to 4 testmsg
    程序运行出错
    java.lang.IllegalStateException: Dialog just created.
    at net.solosky.maplefetion.client.dialog.Dialog.ensureOpened(Dialog.java:129)
    at net.solosky.maplefetion.client.dialog.BasicChatDialog.sendChatMessage(BasicChatDialog.java:82)
    at net.solosky.maplefetion.FetionDemo.send(FetionDemo.java:801)
    at net.solosky.maplefetion.FetionDemo.to(FetionDemo.java:367)
    at net.solosky.maplefetion.FetionDemo.dispatch(FetionDemo.java:983)
    at net.solosky.maplefetion.FetionDemo.mainloop(FetionDemo.java:947)
    at net.solosky.maplefetion.FetionDemo$18.run(FetionDemo.java:923)
    at java.lang.Thread.run(Unknown Source)

    [回复]

    solosky 回复:

    @rain,
    看来是同步问题没有处理好,今天太晚了,明天一早就修正这个问题,再次感谢你的反馈!!

    [回复]

  11. rain
    2010年5月8日10:00

    老大,这个问题你还改呢。等!

    [回复]

  12. 可可
    2010年5月21日16:21

    想请教一下,在处理服务器返回的信令时,如果做到把每一条信令分开并处理?

    [回复]

    solosky 回复:

    这个就是飞信协议层应该做事情了。可以想象在TCP上面多了一个飞信协议层,把TCP交给的一个一个独立的数据包,组装成完整的飞信信令包。
    怎么去解析出一条一条的信令,这是飞信协议规定的。飞信协议类似于HTTP协议,有消息行,消息头,消息行。如果你熟悉HTTP协议就很简单了,如果你不熟悉可以去搜索一下SIP协议,再和Nathan2007的博客对照看就明白了,很简单。

    [回复]

  13. Silence
    2010年7月2日14:05

    请问下,关于状态的!
    好友的状态,0:离线 100:离开 400:在线 600:忙碌
    请问隐身的状态码是多少,谢谢!

    [回复]

    solosky 回复:

    @Silence, 隐身的状态也是0,离线和隐身在客户端是看不出来的。

    [回复]

  14. jim
    2010年12月10日17:46

    飞信对网络的自适应能力很强吗?我们需要在公司网络中使用飞信,使用的是微软的TMG做代理服务器,经常出现大面积的无法登录,我尝试着在TMG上做了any到any允许的策略,结果还是无法登录,各个版本的客户端都是这样,这与他的登录方式有关系吗?

    [回复]

    solosky 回复:

    飞信正常登陆请不要封80,8080,443这三个端口。

    [回复]

  15. jim
    2010年12月10日17:46

    我的QQ:276450,希望与你沟通,谢谢

    [回复]

  16. tiger822
    2010年12月16日22:48

    MapleFetion2.test.jar可否open source ?

    [回复]

    solosky 回复:

    你可以在这里下载完整maplefetion的代码:http://maplefetion.googlecode.com

    [回复]

  17. 2012年1月3日18:34

    chat-friend这个什么含义还不清楚
    ——–
    我估计是,陌生人列表

    [回复]

  18. 2012年1月3日18:53

    我一直,以为这个是心跳包呢! 10几秒一次
    —————
    O fetion.com.cn SIP-C/4.0
    F: 490587802
    I: 26
    Q: 1 O
    N: KeepConnectionBusy

    [回复]