登录 用户中心() [退出] 后台管理 注册
   
您的位置: 首页 >> SoftHub关联区 >> 主题: iOS—XMPP快速登录[zt]     [回主站]     [分站链接]
iOS—XMPP快速登录[zt]
clq
浏览(327) - 2018-08-18 11:53:11 发表 编辑

关键字: xmpp_doc

[2018-08-18 11:53:53 最后更新]
iOS—XMPP快速登录[zt]

来自
https://www.jianshu.com/p/cb6046376ccf
写得是非常好的,和我的观点非常一致. xmpp 本来就是可以做得非常简单的.

clq  2018-08-18 11:53:53 发表 编辑

上一篇文章中,当XMPP需要建立起连接的时候,总共会发送 6 条数据包给Openfire服务器。先来回顾一下:

17:22:41.357  -[XMPPManager xmppStreamWillConnect:] socket正在连接...

17:22:42.100  -[XMPPManager xmppStream:socketDidConnect:] socket连接成功...

17:22:42.102  ①、SEND: <?xml version='1.0'?>

17:22:42.103  ②、SEND: <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' to='192.168.1.1'>

17:22:43.085  RECV: <stream:features xmlns:stream="http://etherx.jabber.org/streams"><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism></mechanisms><auth xmlns="http://jabber.org/features/iq-auth"/></stream:features>

17:22:43.086  -[XMPPManager xmppStreamDidConnect:] [Line 198] xmpp连接成功, 正在授权......

17:22:43.087  ③、SEND: <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN"> APINT4ANBTYg6IJ </auth>
<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN"> APINT4ANBTYg6IJ </auth><resource>iOS_V1.0</resource>

17:22:43.534  RECV: <success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>

17:22:43.534  ④、SEND: <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' to='192.168.1.1'>

17:22:43.870  RECV: <stream:features xmlns:stream="http://etherx.jabber.org/streams"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></stream:features>

17:22:43.871  ⑤、SEND: <iq type="set" id="123BF55A-C6FC-4AA8-A922-E1B869D6D731"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><resource>iOS_V1.0</resource></bind></iq>

17:22:44.261  RECV: <iq xmlns="jabber:client" type="result" id="123BF55A-C6FC-4AA8-A922-E1B869D6D731" to="192.168.1.1/isaw95526287f"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>1024@192.168.1.1/iOS_V1.0</jid></bind></iq>

17:22:44.262  ⑥、SEND: <iq type="set" id="80BA9B44-1247-4219-9F54-0C1E63F424A0"><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>

17:22:44.669  RECV: <iq xmlns="jabber:client" type="result" id="80BA9B44-1247-4219-9F54-0C1E63F424A0" to="1024@192.168.1.1/iOS_V1.0"/>

17:22:44.670  -[XMPPManager xmppStreamDidAuthenticate:] [Line 208] xmpp授权成功。

看这些数据包也发现不了什么问题,但是当产品在线上运行了很久,加上用户量达到一定的规模之后,通过数据监控发现,XMPP连接成功率并不高。于是技术部几个同事开会讨论如何把这个指标提高。经过前后端联调发现,建立连接时客户端并不需要发送那么多条数据包,有几个操作没必要在客户端做,在服务器上操作会更方便,还省了些带宽和降低服务器压力,客户端每发一条数据都会给服务器增加一些压力。

于是一个新名词就出现了,我们把这次优化的登录叫做快速登录。主要的做法是:

    把①去掉,这个数据包貌似只是为了探测网络的,并没有什么用
    ②中的stream:stream包是必须的,为了区别旧版本,多加一个字段v=‘1.0’
    ③中的auth非常重要,是用于鉴权的。这里做一些修改,把resource子节点作为auth节点的属性,并且为了兼容旧版本,这里的资源需要和旧版不一样,服务器端根据这个来判断新旧版本,把resource的值改为iOS_FL_V1.0
    把④去掉
    ⑤和⑥这个步骤都只需要在服务器上做操作

修改之后,整体登录的收发数据包看起来像这样:

11:52:24:022 SEND: <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' xml:lang='en' v='1.0' to='192.168.1.1'>

11:52:24:030 RECV: <stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" v="1.0" from="192.168.1.1" id="m5xmx2f493125" stream1:lang="en" version="1.0"/>

11:52:24:031 RECV: <stream:features xmlns:stream="http://etherx.jabber.org/streams"><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism></mechanisms></stream:features>

11:52:24:044 SEND: <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN" res="iOS_FL_V1.0">APINT4ANBTYg6IJ</auth>

11:52:24:054 RECV: <success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>

客户端只发送了2条数据包即可实现快速登录,是不是简洁了很多。如果客户端需要发送很多数据包才能登录,这期间也许因为网络的原因导致某条数据包没发出去,或者服务器返回的某条数据包无法收到,都会导致无法登录。而快速登录就是为了减少不必要的数据包,增加登录的成功率。

下面讲一下如何修改源码来达到快速登录。当然还是最重要的那个类XMPPStream,根据上面的做法一步步来:

    找到- (void)sendOpeningNegotiation;这个方法的实现,把

    if (![self didStartNegotiation])

    {
    // TCP connection was just opened - We need to include the opening XML stanza
    NSString *s1 = @"<?xml version='1.0'?>";

      NSData *outgoingData = [s1 dataUsingEncoding:NSUTF8StringEncoding];
      
      XMPPLogSend(@"SEND: %@", s1);
      numberOfBytesSent += [outgoingData length];
      
      [asyncSocket writeData:outgoingData
                 withTimeout:TIMEOUT_XMPP_WRITE
                         tag:TAG_XMPP_WRITE_START];
      
      [self setDidStartNegotiation:YES];
    }

这段代码注释。

    同样- (void)sendOpeningNegotiation;这个方法,
    if (myJID_setByClient)
    {
    // 修改这里
    s2 = [NSString stringWithFormat:"<stream:stream xmlns='%@' xmlns:stream='%@' version='1.0' xml:lang='en' v='1.0' to='%@'>", xmlns, xmlns_stream, [myJID_setByClient domain]];
    }
    else if ([hostName length] > 0)
    {
    temp = @"<stream:stream xmlns='%@' xmlns:stream='%@' version='1.0' to='%@'>";
    s2 = [NSString stringWithFormat:temp, xmlns, xmlns_stream, hostName];
    }
    else
    {
    temp = @"<stream:stream xmlns='%@' xmlns:stream='%@' version='1.0'>";
    s2 = [NSString stringWithFormat:temp, xmlns, xmlns_stream];
    }

    修改auth包的内容稍微复杂一些,当Socket连接上了之后,会在- (void)xmppStreamDidConnect:(XMPPStream *)sender;这个代理回调里面调用- (BOOL)authenticateWithPassword:(NSString *)inPassword error:(NSError **)errPtr;进行鉴权登录。跟着这个方法进去,我们app中登录会走else if ([self supportsPlainAuthentication]),进入XMPPPlainAuthentication这个类,需要修改auth包的内容,找到- (BOOL)start:(NSError **)errPtr;这个方法,修改如下:
    ......
    NSXMLElement *auth = [NSXMLElement elementWithName:@"auth" xmlns:@"urn:ietf:params:xml:ns:xmpp-sasl"];
    [auth addAttributeWithName:@"mechanism" stringValue:@"PLAIN"];
    [auth addAttributeWithName:@"res" stringValue:@"iOS_FL_V1.0"];
    [auth setStringValue:base64];
    ......

    当客户端发送了auth包之后,如果成功了,服务器端则会返回success包,在XMPPStream类的- (void)handleAuth:(NSXMLElement *)authResponse;中处理。这个方法的实现有些怪异,明明鉴权成功了,为啥还要发stream包,经过与后端联调发现没有必要再发了,于是做了下判断,把shouldRenegotiate这个变量写死为NO即可,这样就不会发了

通过快速登录,客户端与服务器之间的数据包传送数量少了,经过我们线上几百万用户的使用情况上看,效果还是很明显的,没有出现什么问题,大大的提升了登录成功率。

XMPP连接登录,一直以来坑比较的多,只有在用户量达到一定规模才会显现出来,曾面试过一些人,他们也都有了解XMPP,做过相关的项目,然而问其一些关于连接的问题时,基本上说没有遇到什么问题。这其实不是他们的问题。作为一款IM产品,如果不能正常的聊天,如何谈得上是IM呢。

吃午饭了…

作者:笑谈红尘乱离人
链接:https://www.jianshu.com/p/cb6046376ccf
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。


总数:1 页次:1/1 首页 尾页  
总数:1 页次:1/1 首页 尾页  


所在合集/目录
xmpp协议最小实现合集 更多



发表评论:
文本/html模式切换 插入图片 文本/html模式切换


附件:



NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.

Copyright © 2005-2020 clq, All Rights Reserved
版权所有
桂ICP备15002303号-1