`
jianfulove
  • 浏览: 120030 次
  • 性别: Icon_minigender_1
  • 来自: 湛江
社区版块
存档分类
最新评论

tigase源码分析7:用户连接登录流程

阅读更多
//在看本节之前一定要先了解下xmpp协议,建议仔细看下 tigase源码分析6:了解xmpp协议


//在看下面代码之前,要知道,每一个用户User通过某一资源连接到服务器时,
 //每一个User在不同的资源上登录都各对应着一个IOService,
 //每一个资源对应着一个XMPPResourceConnection,
 //同一个用户User多个XMPPResourceConnection可能共同引用着同一个XMPPSession
public IOService<?> IOService.call() throws IOException {
......
//当socket有数据要处理的时候,进行解析
processSocketData();
if ((receivedPackets() > 0) && (serviceListener != null)) {
	serviceListener.packetsReady(this);
}    // end of if (receivedPackets.size() > 0)
.....
}


protected void XMPPIOService.processSocketData() throws IOException {
.....  
       //解析socket数据
	parser.parse(domHandler, data, 0, data.length);
....

}


public final void SimpleParser.parse(SimpleHandler handler, char[] data, int off, int len) {
.....
 //遇到<stream:stream>
handler.startElement(parser_state.element_name, null, null);
......
}


public void XMPPDomBuilderHandler.startElement(StringBuilder name, StringBuilder[] attr_names,
			StringBuilder[] attr_values) {
......
       //服务端也打开一个对应的<stream:stream>
	service.xmppStreamOpened(attribs);
........
}

protected void XMPPIOService.xmppStreamOpened(Map<String, String> attribs) {
...
String response = serviceListener.xmppStreamOpened(this, attribs);
...
}


public String ClientConnectionManager.xmppStreamOpened(XMPPIOService<Object> serv,
 Map<String,String> attribs) {
....

if (id == null) {
//生成一些属性
 id = UUID.randomUUID().toString();
 serv.getSessionData().put(IOService.SESSION_ID_KEY, id);
 serv.setXMLNS(XMLNS);
 serv.getSessionData().put(IOService.HOSTNAME_KEY, hostname);
 serv.setDataReceiver(JID.jidInstanceNS(routings.computeRouting(hostname)));

 String streamOpenData = prepareStreamOpen(serv, id, hostname);
//给客户端回一个<stream:stream>告诉他服务端也打开了stream
 writeRawData(serv, streamOpenData);
//生成一个新的iq请求packet,主要作用是通知打开session connection
Packet streamOpen = Command.STREAM_OPENED.getPacket(serv.getConnectionId(), serv
 .getDataReceiver(), StanzaType.set, this.newPacketId("c2s-"), Command.DataType.submit);
//设置一些属性
Command.addFieldValue(streamOpen, "session-id", id);
Command.addFieldValue(streamOpen, "hostname", hostname);
Command.addFieldValue(streamOpen, "xml:lang", lang);
//把刚新生成的packet投递到MessageRouter去路由到目的地
addOutPacketWithTimeout(streamOpen, startedHandler, 45l, TimeUnit.SECONDS);
}



       

 

//这是上面生成的一个iq command packet
<iq from="c2s@dell-pc/192.168.3.10_5222_192.168.3.10_53597" type="set" id="c2s--c2s5"
     to="sess-man@dell-pc">
  <command node="STREAM_OPENED" xmlns="http://jabber.org/protocol/commands">
    <x type="submit" xmlns="jabber:x:data">
         <field var="session-id">
          <value>4f0e26c9-aeac-442e-aaea-84c788ab73d2</value>
         </field>
          <field var="hostname">
            <value>192.168.3.10</value>
          </field>
          <field var="xml:lang">
          <value>en</value>
          </field>
    </x>
   </command>
</iq>

 

 

   

//packet被路由到SessionManager后,由继承的QueueListener线程进行处理
QueueListener为内部类,所以他能访问外部类的方法
 public void QueueListener.run() {
  .........
//由于属于command,所以进入以下代码块
  if (packet.isCommand() && (packet.getStanzaTo() != null)
  && compName.equals(packet.getStanzaTo().getLocalpart())
   && isLocalDomain(packet.getStanzaTo().getDomain())) {
	processed = processScriptCommand(packet, results);
	if (processed) {
	Packet result = null;

	while ((result = results.poll()) != null) {
	  addOutPacket(result);
	}
	}
  }
   if (!processed && ((packet = filterPacket(packet, incoming_filters)) != null)) {
	processPacket(packet);//此方法是执行真正的实现类的方法,
    }
.........
}

//再执行到processCommand
public void SessionManager.processPacket(final Packet packet) {
	//为command,则执行processCommand
	 if (packet.isCommand() && processCommand(packet)) {
			packet.processedBy("SessionManager");

			// No more processing is needed for command packet
			return;
		}    // end of if (pc.isCommand())

		XMPPResourceConnection conn = getXMPPResourceConnection(packet);

...
		processPacket(packet, conn);
	}


//private SessionOpenProc   sessionOpenProc  = null;
protected boolean SessionManager.processCommand(Packet pc) {
....
Iq      iqc= (Iq) pc;
XMPPResourceConnection connection = connectionsByFrom.get(iqc.getFrom());
  switch (iqc.getCommand()) {
....
case STREAM_OPENED : {		
 //获取session processor的处理线程集
  ProcessingThreads<ProcessorWorkerThread> pt = workerThreads.get(sessionOpenProc.id());
   if (pt == null) {
      pt = workerThreads.get(defPluginsThreadsPool);
    }
    //把packet交给session processor插件来进行下一步的处理,它是运行在单独的线程上的。
    pt.addItem(sessionOpenProc, iqc, connection);
    processing_result = true;
  }



public void SessionOpenProc.process(Packet packet, XMPPResourceConnection session,
	NonAuthUserRepository repo, Queue<Packet> results, Map<String, Object> settings)
				throws XMPPException {
...
 //每一个客户端都会生成一个对应的XMPPResourceConnection 资源连接器,它持有XMPPSession的引用
  conn = createUserSession(packet.getFrom(), hostname);
  conn.setSessionId(Command.getFieldValue(packet, "session-id"));
  conn.setDefLang(Command.getFieldValue(packet, "xml:lang"));
..
 //回一个应答packet
  fastAddOutPacket(packet.okResult((String) null, 0));
}


protected XMPPResourceConnection SessionManager.createUserSession(JID conn_id, String domain) throws TigaseStringprepException {
  XMPPResourceConnection connection = new XMPPResourceConnection(conn_id,
				user_repository, auth_repository, this);
//放进SessionManager.connectionsByFrom中,以便在processPacket(..)中得到相关packet的conn
   connectionsByFrom.put(conn_id, connection);
  return connection;
 }

 

<iq from="c2s@dell-pc/192.168.3.10_5222_192.168.3.10_64739" type="get" id="ead3ca01-9469-414f-9f0a-a7a52c164a72" to="sess-man@dell-pc"><command node="GETFEATURES" xmlns="http://jabber.org/protocol/commands"/>
</iq>

<iq from="sess-man@dell-pc" type="result" id="ead3ca01-9469-414f-9f0a-a7a52c164a72" to="c2s@dell-pc/192.168.3.10_5222_192.168.3.10_64739"><command node="GETFEATURES" xmlns="http://jabber.org/protocol/commands"><ver xmlns="urn:xmpp:features:rosterver"/></command>
</iq>

<iq from="sess-man@dell-pc" type="result" id="73c47636-536c-4f6b-a306-8ff912313497" to="c2s@dell-pc/192.168.3.10_5222_192.168.3.10_49257"><command node="GETFEATURES" xmlns="http://jabber.org/protocol/commands"><ver xmlns="urn:xmpp:features:rosterver"/><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism></mechanisms><register xmlns="http://jabber.org/features/iq-register"/><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression><auth xmlns="http://jabber.org/features/iq-auth"/></command>
</iq>

 

<!-- 客户端发来认证请求-->
<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">ADc4OTQ1NgA3ODk0NTY=</auth>
<!--服务端产生的对应的iq 作为流转命令,不返回给客户端的-->
<iq from="sess-man@dell-pc" type="set" id="tig2" to="c2s@dell-pc/192.168.3.10_5222_192.168.3.10_49257"><command node="USER_LOGIN" xmlns="http://jabber.org/protocol/commands"><x type="submit" xmlns="jabber:x:data"><field var="user-jid"><value>789456@192.168.3.10</value></field></x></command></iq>
<!-- 认证成功返回给客户端的-->
<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>

   

   当服务端接收到<auth>认证请求后,执行SaslAuth 认证处理通过以后,则生成用户对应的XMPPSession

 

public void SaslAuth.process(final Packet packet, final XMPPResourceConnection session,final NonAuthUserRepository repo, final Queue<Packet> results, final Map<String, Object> settings) {
.....
if (ss.isComplete() && (ss.getAuthorizationID() != null)) {
 .....
//检查有没有XMPPSession,没有则创建一个新的绑定相关的属性
 session.authorizeJID(jid, anonymous);
//返回一个<success>成功标志的packet
results.offer(packet.swapFromTo(createReply(ElementType.success,challengeData),null,null));

}

  public void XMPPResourceConnection.authorizeJID(BareJID jid, boolean anonymous) {
		authState    = Authorization.AUTHORIZED;
		is_anonymous = anonymous;
		loginHandler.handleLogin(jid, this);
		login();
	}

    public void SessionManager.handleLogin(BareJID userId, XMPPResourceConnection conn) {
	registerNewSession(userId, conn);
	}

    protected void SessionManager.registerNewSession(BareJID userId, XMPPResourceConnection conn) {
   .....
       //一个用户在不同一资源上登录,共用这个xmppsession
       XMPPSession session = sessionsByNodeId.get(userId);
         if (session == null) {
	    session = new XMPPSession(userId.getLocalpart());
	    sessionsByNodeId.put(userId, session);
      ....
         } else {
        // Check all other connections whether they are still alive....
        //检查session.activeResources中其它的XMPPResourceConnection是否有效的
        List<XMPPResourceConnection> connections = session.getActiveResources();
        .........
       }
       //session和connection相互关联起来,双方都持有对方的引用
       session.addResourceConnection(conn);

if ((!"USER_STATUS".equals(conn.getSessionId())) &&!conn.isServerSession() &&!conn
						.isTmpSession()) {
  //生成一个USER_LOGIN 事件的命令packet,好让生成的jid关联到用户的IOService上		
 Packet user_login_cmd = Command.USER_LOGIN.getPacket(getComponentId(), 
  conn.getConnectionId(), StanzaType.set, conn.nextStanzaId(), Command.DataType.submit);
  Command.addFieldValue(user_login_cmd, "user-jid", userId.toString());
  ddOutPacket(user_login_cmd);
}
   .....
 }



 

 

 

 

protected void ClientConnectionManager.processCommand(Packet packet) {
		XMPPIOService<Object> serv = getXMPPIOService(packet);
switch (iqc.getCommand()) {
case GETFEATURES :
..
break;
case USER_LOGIN :
  String jid = Command.getFieldValue(iqc, "user-jid");
 .....
  serv.setUserJid(jid);
}

       下一步,客户端会再次打开流,服务端也会打开一个新的流,这时客户端会请求绑定资源名称

<iq type="set" id="bind_1">
<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
<resource>DELL-PC</resource>
</bind>
</iq>

    服务端 BindResource (绑定插件)会处理这个packet,所以只要明白,tigase都是基于插件和组件组合来处理请求的,不同的插件来处理不同的请求,我们也可以开发相关的插件来处理我们自定义的请求了。

     

分享到:
评论

相关推荐

    tigase-utils-3.5.1.jar

    tigase相关jar包

    tigase-web-chat

    在描述中提到“官方下载真实有效”,这意味着你可以从Tigase项目的官方网站获取到这个Web Chat的源码或者预编译的版本,确保软件的安全性和可靠性。官方提供的软件通常会经过严格的测试和更新,能够避免第三方源可能...

    tigase 内部处理流程

    通过对Tigase启动流程、消息路由器以及客户端连接管理的深入分析,我们不仅了解了Tigase的核心组件是如何工作的,还明白了它们之间如何协作以提供稳定可靠的XMPP服务。这种深入的技术解析有助于开发者更好地理解...

    tigase-server-tigase-server-8.0.0.zip 源码

    7. **API接口**:Tigase提供了一套API接口,使得开发者可以轻松地开发插件或者集成到其他系统中。 8. **事件驱动编程**:Tigase服务器利用事件驱动模型来处理网络事件,如新连接、消息发送和接收等,这种模式能够...

    Spark客户端连接Tigase

    Spark连接Tigase服务器,完整的步骤,很清晰的看到。大家可以参考。

    tigase http-api 源码部署

    接下来,需要添加tigase-web-ui.war包到项目中,这个包包含了后台管理界面,它是Tigase服务器的Web用户界面,能够通过Web浏览器来管理服务器。该war包可以在Tigase的Maven仓库中找到,下载链接为 ***。 然后,修改...

    XMPP_tigase_IM服务部署安装

    Tigase的核心优势在于其能够支持大量的并发用户连接,并通过集群技术实现高可用性和负载均衡。这使得Tigase成为企业和组织内部即时通讯解决方案的理想选择。 #### 相关项目比较 除了Tigase之外,还有一些其他的...

    tigase快速配置

    2. Git:用于从官方仓库克隆Tigase源代码,虽然我们这里提到的是快速部署,但了解如何获取最新源码总是有好处的。 接下来,我们将详细介绍快速配置和部署Tigase的步骤: 1. **下载Tigase**:您可以从Tigase官方...

    tigase组件

    7. **tigase-pubsub**:发布订阅(PubSub)是XMPP的一项扩展,允许用户和应用程序订阅和发布事件或数据。Tigase的PubSub组件实现了这一标准,支持节点创建、订阅、发布和事件推送,广泛应用于实时通知和数据共享场景...

    tigase-server:高度优化,高度模块化和非常灵活的XMPPJabber服务器

    高度优化,高度模块化且非常灵活的XMPP ... -多用户聊天: -发布-订阅: 和个人事件协议: -SOCKS5字节流: -用于Tigase的组件 -该组件基于JDK内置HTTP服务器,提供易于使用的HTTP端点进行服务器管理和集成。 -高性

    基于tigase的独立IM系统.zip

    7. **API与XMPP兼容**:开发者可以使用XMPP协议或者Tigase提供的API进行二次开发。 **系统架构与组件:** 1. **服务器核心**:负责处理网络连接,管理用户会话,处理数据包转发。 2. **认证模块**:处理用户的登录...

    tigase-local

    2. **用户管理**:Tigase支持多种用户存储方式,包括内存、文件、数据库等。在`tigase.conf`中配置用户存储源。 3. **安全设置**:为了确保安全,应启用SSL/TLS加密,并配置相应的证书。 **四、Tigase子文件解释**...

    tigase 集群设置

    7. 数据库配置:Tigase集群需要数据库来存储用户信息和消息历史。数据库配置通过 "--user-db" 和 "--user-db-uri" 参数来指定,包括数据库类型、数据库URI、用户名、密码以及字符编码设置。 8. 组件配置:Tigase...

    Tigase 概述

    Tigase 概述 Tigase 是一个功能强大且灵活的 XMPP 服务器,提供了许多出色的特性和功能,以下是其主要特点和...Tigase 是一个功能强大且灵活的 XMPP 服务器,提供了许多出色的特性和功能,能够满足不同用户的需求。

    xmpp之java服务端实现tigase整合项目源代码

    该资源是整合了tigase的java服务端源代码,环境为:idea + gradle + postgresql 注意,这部分项目只包括java源代码,而数据库备份将在下一个资源打包上传,有疑问请阅读相关博文: ...

    tigase monitor配置

    完成以上步骤后,Tigase Monitor应能成功连接到Tigase服务器并开始监控。你可以通过运行Monitor应用来查看服务器的实时状态,如在线用户数、内存使用情况、CPU负载等,从而及时发现和解决可能的问题,保障服务的稳定...

    tigase开发指南.pdf

    tigase服务器的数据库存储了用户信息、权限信息、离线消息信息、在线离线状态信息等数据,但是有些数据我们不需要让tigase存储、更新,比如在线离线状态信息,如果每个用户登录、登出都让tigase更新表的字段,并发高...

    tigase-server-8.0.0-b10083-dist-max.zip

    Tigase服务器是一款开源的XMPP(Extensible Messaging and Presence Protocol)服务器软件,广泛应用于即时通讯、在线状态管理和多用户聊天室等场景。标题中的“tigase-server-8.0.0-b10083-dist-max.zip”指的是...

    tigase-server 组件

    6. **性能优化**:通过调整服务器配置,如并发连接数、内存分配等,可以优化Tigase的性能,使其能处理更多的并发用户。 7. **故障排查**:理解和使用Tigase的日志系统,有助于定位和解决服务器运行中的问题。 8. *...

    Tigase Server 7.0.1 源代码

    4. **存储层**:Tigase Server支持多种数据库后端,如MySQL、PostgreSQL等,用于存储用户信息、会话状态等数据。源代码中的数据库访问层确保了与各种数据库系统的兼容性。 5. **安全层**:为了保障通信安全,Tigase...

Global site tag (gtag.js) - Google Analytics