Archive for the 'web2.0-即时通信' Category


手机客户端IM技术实现思考3-聚合化生存

    目前互联网上的IM市场竞争极其的激烈,整个市场的垄断格局基本上形成,要做一个大而全的IM基本上很难了,当然在一些垂直行业一样存在较大的机会,例如阿里巴巴的贸易通。

    在无线互联网上目前IM竞争相对还不是很惨烈,但那些在互联网占据核心优势的企业具有先天的竞争优势,等到无线互联网相对成熟时候,这些公司全力大举杀入,初创性的公司在技术、资源调度能力、市场影响力等方面都无力与其竞争。

    既然这样对于后来者来说是否还需要做IM,在IM市场是否还有机会呢?

    我觉得在无线互联网领域IM还有很大的市场机会,而且IM是任何无线互联网公司都应当做的。当然需要在产品定位上及产品形式做到与传统IM的区隔。要做到区隔需要从用户需求的原点开始,进行用户群细分。  

    与互联网IM不同,手机终端本身最大的功能还是通话功能,而IM基于VOIP的协议可以较好解决用户低成本,而通话费用是运营商们利润根本,因此这也是移动飞信、联通超信(网通灵信)、电信等运营商的IM不可能在完全正常的环境下成长起来。当然在这一点上,对于做IM的机会都一样的。

    与传统的IM(姑且叫其为IM1.0)不同,新来者的IM(IM 2.0)的竞争策略重点不应当是实时通信功能,这一点传统的IM1.0的厂商已经做得足够的好了。IM2.0要做到突围,我觉得应该是重点强化IM的SNS化、媒体草根化(去中心化)、3G化的特性:

  • SNS化:通过开放的多通信协议支持来协助用户整合各种零散分布在各个社区和渠道的关系链,成为用户的SNS中心。这里的多协议不单纯是对IM的多协议(MSN、QQ、Yahoo Messenger、Gtalk、ICQ等)支持,还包括开放社区协议(Open Social、OpenID、OAuth)
  • 媒体草根化(去中心化):用户通过Blog、Twitter、Youtube等草根社会化媒体工具来展现自我,但服务去中心化后,意味着用户使用的服务分布在不同的社区中,用户需要在不同社区间不停切换身份。同时这些UGC的内容成千上万,没有人有精力天天去及时摘取最优的内容,通过IM 2.0聚合这些优质的内容来帮助用户解决媒体草根化后的各种难题。
  • 3G化:随着3G市场及技术的逐步成熟,基于3G的各种创新性应用及服务必将浮现,这一点对于IM1.0、IM2.0而言,大家的起点都是一样的。

    这样看来,IM2.0感觉不是在做IM,而是做社区、做媒体了。没错,我认为对于初创性的互联网公司而言,仍然指望从即时通信功能上去与IM1.0的厂商竞争。那基本上没有市场机会。在所提供的IM没有明显的产品优势、技术优势的情况下,没有任何一个用户愿意去使用一个全新的工具,重新构建自己的关系链。同时初创性公司也应当避免传统IM厂商的大而全的思路,从IM、社区、内容什么都要自己做。

   对于初创性互联网公司而言,在初期可以通过通过IM这个接入工具来聚合现有的各种优质的社区服务及内容,然后逐步引入自己具有特色的核心服务,最终形成自己的核心竞争力。

    这就是所谓的聚合化生存。

手机客户端IM技术实现思考2-我的IM2.0

我的IM2.0

 

手机客户端IM技术实现思考

手软客户端技术预研说明

 

Jabber协议分析之Subscriptions运行机制-Presence subscription

    手机客户端需要实现即时通信功能,在通信协议上采用开放的Jabber(XMPP)协议,整个XMPP协议最为核心也是最为复杂的部分是Subscription的运行机制,抓取了一下相关的通信协议报文,供开发时候参考。

  

1. 测试环境

1.1. 测试软件环境:

    Jabber服务器:Openfire 3.5.2

    Jabber客户端:Spark 2.5.8

抓包:Wireshark

1.2. 服务器环境:

    Jabber服务器:192.168.1.12,安装Openfire,域为home1

    Jabber用户客户端:192.168.1.10,安装Spark客户端,Jabber用户为chuanliang。

    Jabber联系人客户端:192.168.1.11,安装Spark客户端,Jabber用户为liangchuan

1.3. 测试场景:

测试1:

    Jabber用户chuanliang和Jabber联系人liangchuan被彼此的presence订阅,且允许把彼此加入自己的Roster

测试2

    Jabber联系人liangchuan接受Jabber用户chuanliang的订阅,但是不允许chuanliang加入自己的Roster

测试3

    Jabber联系人liangchuan不接受Jabber用户chuanliang的订阅,同时不允许chuanliang加入自己的Roster

以测试用例“测试1”说明一下测试过程:

1、 chuanliang@home1在192.168.1.10客户端上新增联系人liangchuan@home1

2、 liangchuan@home1在192.168.1.11客户端上“准许chuanliang@home1新增liangchuan@home1到chuanlian的联系人名单中”,同时”Add user to liangchuan’s  roster”

clip_image002

3、 chuanliang@home1在192.168.1.10客户端上“准许liangchuan@home1新增chuanliang@home1到chuanlian的联系人名单中”,同时”Add user to chuanliang’s  roster”

clip_image004

2. 测试1- contact accept subscription and allow add user to it’s roster

2.1. Jabber用户客户端发送一个type=’set’ 的Roster Update请求给Jabber服务器端

Ø 192.168.1.10->192.168.1.12

Jabber用户客户端发送一个<iq/>包给Jabber服务器端,其jabber:iq:roster名字空间中包含一个type=’set’,用于更新自己的roster

<iq id="7SJ55-63" type="set">

    <query xmlns="jabber:iq:roster">

        <item jid="liangchuan@home1" name="liangchuan">

            <group>Friends</group>

        </item>

    </query>

</iq>

Ø 192.168.1.12->192.168.1.10

Jabber用户客户端从服务器接收到一个“roster push”,产生一个新的roster条目,其subscription状态置为“none”:

<iq type="set" id="308-51" to="chuanliang@home1/spark">

    <query xmlns="jabber:iq:roster">

        <item jid="liangchuan@home1" name="liangchuan" subscription="none">

            <group>Friends</group>

        </item>

    </query>

</iq>

Ø 192.168.1.12->192.168.1.10

Jabber用户客户端在成功的情况下,从服务器接收到一个<iq/>包,其type=’result’。

<iq type="result" id="7SJ55-63" to="chuanliang@home1/spark"/>

2.2. Jabber用户客户端发送一个type=’subscribe’的<presence/>的包给联系人客户端

Jabber用户客户端发送一个type=’subscribe’的<presence/>的包给联系人(发送给到Jabber服务器)

Ø 192.168.1.10->192.168.1.12

<presence id="7SJ55-64" to="liangchuan@home1" type="subscribe"/>

Ø 192.168.1.12->192.168.1.10

Jabber用户客户端接着从服务器收到包含联系人待定子状态的’none’订阅状态的“roster push”;这个待定子状态在其联系人名单中包含一个ask=’subscribe’属性:

<iq type="set" id="132-52" to="chuanliang@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan" ask="subscribe" subscription="none">

<group>Friends</group>

</item>

</query>

</iq>

2.3. Jabber服务器发送一个type=’subscribe’的<presence/>的Roster push包给联系人客户端

Ø 192.168.1.12->192.168.1.11

Jabber服务器在接收到192.168.1.10发送的type=’subscribe’的<presence/>的包后,然后发送一个type=’subscribe’的<presence/>的包给联系人客户端

<presence id="7SJ55-64" to="liangchuan@home1" type="subscribe" from="chuanliang@home1"/>

Ø 192.168.1.11->192.168.1.12

Jabber联系人客户端发送一个<iq/>包给Jabber服务器,其jabber:iq:roster名字空间中包含一个type=’set’,用于更新自己的roster:

<iq id="8SAVC-26" type="set">

<query xmlns="jabber:iq:roster">

<item jid="chuanliang@home1" name="chuanliang">

<group>Friends</group>

</item>

</query>

</iq>

Ø 192.168.1.12->192.168.1.11

Jabber联系人客户端从服务器接收到一个<iq/>包,其type=’result’

<iq type="result" id="8SAVC-26" to="liangchuan@home1/spark"/>

2.4. Jabber联系人客户端发送一个type=’subscribe’的<presence/>的包给用户客户端

此部分请求发生在联系人客户端“准许chuanliang@home1新增liangchuan@home1到chuanlian的联系人名单中”时候同时选择了:“Add user to liangchuan’s  roster”选项。如果没有选择,则无此部分请求。

Ø 192.168.1.11->192.168.1.12

<presence id="8SAVC-27" to="chuanliang@home1" type="subscribe"/>

Ø 192.168.1.12->192.168.1.10

服务器传递请求给Jabber用户端

<presence id="8SAVC-27" to="chuanliang@home1" type="subscribe" from="liangchuan@home1"/>

Ø 192.168.1.12->192.168.1.10

<iq type="set" id="867-55" to="chuanliang@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan" subscription="to">

<group>Friends</group>

</item>

</query>

</iq>

2.5. Jabber联系人客户端接收订阅请求,发送一个type=’subscribed’的<presence/>的包给用户客户端

联系人下一步要做的就是决定是否接受订阅请求。我们假定联系人接受订阅请求

Ø 192.168.1.11->192.168.1.12

联系人的Jabber客户端发送一个type=’subscribed’的<presence/>的包给Jabber用户(通过服务器端)

<presence id="8SAVC-28" to="chuanliang@home1" type="subscribed"/>

Ø 192.168.1.12->192.168.1.10

<presence id="8SAVC-28" to="chuanliang@home1" type="subscribed" from="liangchuan@home1"/>

<presence id="8SAVC-6" from="liangchuan@home1/spark" to="chuanliang@home1/spark">

<status/>

<priority>1</priority>

</presence>

Ø 192.168.1.12->192.168.1.11

联系人的Jabber客户端从服务器接收一个“roster push”包含Jabber用户的条目,其中subscription状态置为“from”

<iq type="set" id="14-54" to="liangchuan@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="chuanliang@home1" name="chuanliang" ask="subscribe" subscription="from">

<group>Friends</group>

</item>

</query>

</iq>

2.6. Jabber用户客户端接收订阅请求,发送一个type=’subscribed’的<presence/>的包给联系人客户端

Ø 192.168.1.10->192.168.1.12

<presence id="7SJ55-65" to="liangchuan@home1" type="subscribed"/>

Ø 192.168.1.12->192.168.1.10

<iq type="set" id="382-56" to="chuanliang@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan" subscription="both">

<group>Friends</group>

</item>

</query>

</iq>

Ø 192.168.1.12->192.168.1.11

<iq type="set" id="697-57" to="liangchuan@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="chuanliang@home1" name="chuanliang" subscription="both">

<group>Friends</group>

</item>

</query>

</iq>

Ø 192.168.1.12->192.168.1.11

<presence id="7SJ55-65" to="liangchuan@home1" type="subscribed" from="chuanliang@home1"/>

<presence id="7SJ55-51" from="chuanliang@home1/spark" to="liangchuan@home1/spark">

<status/>

<priority>1</priority>

</presence>

3. 测试2- contact accept subscribption and not allow add user to it’s roster

3.1. Jabber用户客户端发送一个type=’set’ 的Roster Update请求给Jabber服务器端

Ø 192.168.1.10->192.168.1.12

Jabber用户客户端发送一个<iq/>包给Jabber服务器端,其jabber:iq:roster名字空间中包含一个type=’set’,用于更新自己的roster

<iq id="xHk99-51" type="set">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan">

<group>Friends</group>

</item>

</query>

</iq>

Ø 192.168.1.12->192.168.1.10

Jabber用户客户端从服务器接收到一个“roster push”,产生一个新的roster条目,其subscription状态置为“none”:

<iq type="set" id="133-130" to="chuanliang@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan" subscription="none">

<group>Friends</group>

</item>

</query>

</iq>

Ø 192.168.1.12->192.168.1.10

Jabber用户客户端在成功的情况下,从服务器接收到一个<iq/>包,其type=’result’。

<iq type="result" id="xHk99-51" to="chuanliang@home1/spark"/>

3.2. Jabber用户客户端发送一个type=’subscribe’的<presence/>的包给联系人客户端

Jabber用户客户端发送一个type=’subscribe’的<presence/>的包给联系人(发送给到Jabber服务器)

Ø 192.168.1.10->192.168.1.12

<presence id="xHk99-52" to="liangchuan@home1" type="subscribe"></presence>

Ø 192.168.1.12->192.168.1.10

Jabber用户客户端接着从服务器收到包含联系人待定子状态的’none’订阅状态的“roster push”;这个待定子状态在其联系人名单中包含一个ask=’subscribe’属性:

<iq type="set" id="35-132" to="chuanliang@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan" ask="subscribe" subscription="none">

<group>Friends</group>

</item>

</query>

</iq>

3.3. Jabber服务器发送一个type=’subscribe’的<presence/>的Roster push包给联系人客户端

Ø 192.168.1.12->192.168.1.11

Jabber服务器在接收到192.168.1.10发送的type=’subscribe’的<presence/>的包后,然后发送一个type=’subscribe’的<presence/>的包给联系人客户端

<presence id="xHk99-52" to="liangchuan@home1" type="subscribe" from="chuanliang@home1"/>

3.4. Jabber联系人客户端接收订阅请求,发送一个type=’subscribed’的<presence/>的包给用户客户端

联系人下一步要做的就是决定是否接受订阅请求。我们这里联系人接受订阅请求,但是取消”Add user to chuanliang’s  roster”操作。

Ø 192.168.1.11->192.168.1.12

联系人的Jabber客户端发送一个type=’subscribed’的<presence/>的包给Jabber用户(通过服务器端)

<presence id="8SAVC-90" to="chuanliang@home1" type="subscribed"></presence>

Ø 192.168.1.12->192.168.1.10

<presence id="8SAVC-90" to="chuanliang@home1" type="subscribed" from="liangchuan@home1"/>

<presence id="8SAVC-30" from="liangchuan@home1/spark" to="chuanliang@home1/spark">

<status/>

<priority>1</priority>

</presence>

Ø 192.168.1.12->192.168.1.11

联系人的Jabber客户端从服务器接收一个“roster push”包含Jabber用户的条目,其中subscription状态置为“from”

<iq type="set" id="585-135" to="liangchuan@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="chuanliang@home1" subscription="from"/>

</query>

</iq>

4. 测试3- contact not accept subscription and  not allow add user to it’s roster

4.1. Jabber用户客户端发送一个type=’set’ 的Roster Update请求给Jabber服务器端

Ø 192.168.1.10->192.168.1.12

Jabber用户客户端发送一个<iq/>包给Jabber服务器端,其jabber:iq:roster名字空间中包含一个type=’set’,用于更新自己的roster

<iq id="n7NDl-39" type="set">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan">

<group>Friends</group>

</item>

</query>

</iq>

Ø 192.168.1.12->192.168.1.10

Jabber用户客户端从服务器接收到一个“roster push”,产生一个新的roster条目,其subscription状态置为“none”:

<iq type="set" id="321-250" to="chuanliang@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan" subscription="none">

<group>Friends</group>

</item>

</query>

</iq>

Ø 192.168.1.12->192.168.1.10

Jabber用户客户端在成功的情况下,从服务器接收到一个<iq/>包,其type=’result’。

<iq type="result" id="n7NDl-39" to="chuanliang@home1/spark"/>

4.2. Jabber用户客户端发送一个type=’subscribe’的<presence/>的包给联系人客户端

Jabber用户客户端发送一个type=’subscribe’的<presence/>的包给联系人(发送给到Jabber服务器)

Ø 192.168.1.10->192.168.1.12

<presence id="n7NDl-40" to="liangchuan@home1" type="subscribe"/>

Ø 192.168.1.12->192.168.1.10

Jabber用户客户端接着从服务器收到包含联系人待定子状态的’none’订阅状态的“roster push”;这个待定子状态在其联系人名单中包含一个ask=’subscribe’属性:

<iq type="set" id="942-252" to="chuanliang@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan" ask="subscribe" subscription="none">

<group>Friends</group>

</item>

</query>

</iq>

4.3. Jabber服务器发送一个type=’subscribe’的<presence/>的Roster push包给联系人客户端

Ø 192.168.1.12->192.168.1.11

Jabber服务器在接收到192.168.1.10发送的type=’subscribe’的<presence/>的包后,然后发送一个type=’subscribe’的<presence/>的包给联系人客户端

<presence id="n7NDl-40" to="liangchuan@home1" type="subscribe" from="chuanliang@home1"/>

4.4. Jabber联系人客户端接收订阅请求,发送一个type=’ unsubscribe’的<presence/>的包给用户客户端

联系人下一步要做的就是决定是否接受订阅请求。我们这里联系人接受订阅请求,但是取消”Add user to chuanliang’s  roster”操作。

Ø 192.168.1.11->192.168.1.12

联系人的Jabber客户端发送一个type=’ unsubscribe的<presence/>的包给Jabber用户(通过服务器端)

<presence id="8SAVC-116" to="chuanliang@home1" type="unsubscribe"/>

Ø 192.168.1.12->192.168.1.10

<presence id="8SAVC-116" to="chuanliang@home1" type="unsubscribe" from="liangchuan@home1"/>

Ø 192.168.1.12->192.168.1.11

联系人的Jabber客户端从服务器接收一个“roster push”包含Jabber用户的条目,其中subscription状态置为“remove”

<iq type="set" id="190-258" to="liangchuan@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="chuanliang@home1" subscription="remove"/>

</query>

</iq>

4.5. Jabber用户客户端发送取消订阅请求,发送一个subscription =’ remove’的<iq/>的包给服务器端

Ø 192.168.1.10->192.168.1.12

用户的Jabber客户端发送一个subscription="remove"的包给服务器,取消订阅

<iq id="n7NDl-41" type="set">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" name="liangchuan" subscription="remove" ask="subscribe">

<group>Friends</group>

</item>

</query>

</iq>

Ø 192.168.1.12->192.168.1.10

<iq type="set" id="872-256" to="chuanliang@home1/spark">

<query xmlns="jabber:iq:roster">

<item jid="liangchuan@home1" subscription="remove"/>

</query>

</iq>

Ø 192.168.1.12->192.168.1.10

<iq type="result" id="n7NDl-41" to="chuanliang@home1/spark"/>

5. 参考文档

http://www.xmpp.org/extensions/xep-0162.html

http://tools.ietf.org/html/rfc3921

http://www.xmpp.org/extensions/xep-0144.html