博客专区 > greki 的博客 > 博客详情
greki 发表于4年前
  • 发表于 4年前
  • 阅读 985
  • 收藏 4
  • 点赞 0
  • 评论 0


摘要: tigase内部处理(2):packet流转

在tigase内部处理(1):启动 里有体现http://my.oschina.net/greki/blog/275256










  • socketReadThread和socketWriteThread循环selector.select(),得到selectionKey--->XMPPIOService放到队列forCompletion;
  • forCompletion的XMPPIOService,通过completionService.submit(serv)提交执行,调用XMPPIOService.call();
  • XMPPIOService.call(),完成了接收的socket报文到packet,作为packet在内部处理的入口(后面介绍这些处理);
  • ResultsListener根据XMPPIOService.call()返回的XMPPIOService对象,如果对象不为空重新放回到waiting列表(用于重新注册到clientsSel(selector))这里有点绕,也没太明白,好像是为了回避一个jvm bug;


  •     从XMPPIOService.call();
if ((receivedPackets() > 0) && (serviceListener != null)) {
	serviceListener.packetsReady(this);//serviceListener 这里是clientConnectManager;在connectionOpenTrhead里设置
  • processSocketData()把报文转成xml element;再把element转成对应的packet;
while ((elem = elems.poll()) != null) {
  Packet pack = Packet.packetInstance(elem);//Message、Presence、IQ、其他Packet
  addReceivedPacket(pack);//puts processing results(packet) to queue(receivedPackets),
   sendAck(pack);//ack 模式,收到后发送ack
  • serviceListener.packetsReady()--->clientConnectManager.packetsReady()--->processSocketData([这步设置了packet.to和from属性,在message_router的时候用到])-->addOutPacket(packet)-->放到c2s.out_queues;
  • c2s.out_queues由QueueListener线程来读取处理;
if ((packet = filterPacket(packet, outgoing_filters)) != null) {//out_filter处理	
  • processOutPacket()//By default this method just copies the given packet between queue
if (parent != null) {//parent指message_router,在初始化的时候设置
     parent.addPacket(packet);---->clientConnectManager一定是走这里,把packet构建完成后,交给messageRouter 来处理,添加到它的in_queue; } else {
     // It may happen for MessageRouter and this is intentional

  •  messageRouter对他的in_queue里的packet,被QueueListener线程轮训,主要调用messageRouter.processPacket()

ServerComponent comp = getLocalComponent(packet.getTo());//根据to属性,查找local的component,普通聊天,一般是路由到SessionManager组件

if (comp != null) {  Queue<Packet> results = new ArrayDeque<Packet>();

	if (comp == this) {

		// This is addressed to the MessageRouter itself. Has to be processed
		// separately to avoid recurential calls by the packet processing
		// method.
		processPacketMR(packet, results);
	} else {

		// All other components process the packet the same way.
		comp.processPacket(packet, results);//调用component处理
	if (results.size() > 0) {//结果有返回继续,添回答到in_queue
		for (Packet res : results) {

			// No more recurrential calls!!

			// processPacket(res);
		}    // end of for ()

	// If the component is found the processing ends here as there can be
	// only one component with specific ID.

// This packet is not processed yet
// The packet can be addressed to just a domain, one of the virtual hosts
// The code below finds all components which handle packets addressed
// to a virtual domains (implement VHostListener and return 'true' from
// handlesLocalDomains() method call)
String            host  = packet.getTo().getDomain();
ServerComponent[] comps = getComponentsForLocalDomain(host);//local找不到服务器组件,到对应的集群的其他host查询

if (comps == null) {

	// Still no component found, now the most expensive lookup.
	// Checking regex routings provided by the component.
	comps = getServerComponentsForRegex(packet.getTo().getBareJID().toString());
if ((comps == null) &&!isLocalDomain(host)) {

	// None of the component want to process the packet.
	// If the packet is addressed to non-local domain then it is processed by
	// all components dealing with external world, like s2s
	comps = getComponentsForNonLocalDomain(host);

// Ok, if any component has been found then process the packet in a standard
// way
if (comps != null) {

	// Processing packet and handling results out
	Queue<Packet> results = new ArrayDeque<Packet>();

	for (ServerComponent serverComponent : comps) {
		if (log.isLoggable(Level.FINEST)) {
			log.log(Level.FINEST, "2. Packet will be processed by: {0}, {1}",
					new Object[] { serverComponent.getComponentId(),
					packet });
		serverComponent.processPacket(packet, results);
		if (results.size() > 0) {
			for (Packet res : results) {

				// No more recurrential calls!!

				// processPacket(res);
			}    // end of for ()
} else {

	// No components for the packet, sending an error back
	if (log.isLoggable(Level.FINEST)) {
		log.finest("There is no component for the packet, sending it back");
	try {
				"There is no service found to process your request.", true));
	} catch (PacketErrorTypeException e) {

		// This packet is to local domain, we don't want to send it out
		// drop packet :-(
		log.warning("Can't process packet to local domain, dropping..." + packet



ProcessorWorkerThread 调用 

void process( Packet packet, XMPPResourceConnection session,
NonAuthUserRepository repo, Queue<Packet> results,
Map<String, Object> settings ) throws XMPPException;


Objects of this class carry a single XMPP packet (stanza). The XMPP stanza is carried as an XML element in DOM structure by the Packet object which contains some extra information and convenience methods to quickly access the most important stanza information.
// packet是xmpp stanza封装对象

The stanza is accessible directly through the getElement() method and then it can be handles as an XML object. 
Please note! Even though the Packet object and carried the stanza Element is not unmodifiable it should be treated as such. This particular Packet can be processed concurrently at the same time in different components or plugins of the Tigase server. Modifying it may lead to unexpected and hard to diagnose behaviors. Every time you want to change or update the object you should obtaina a copy of it using one of the utility methods: copyElementOnly(), swapFromTo(...), errorResult(...), okResult(...), swapStanzaFromTo(...)

There are no public constructors for the class, instead you have to use factory methods: packetInstance(...) which return instance of one of the classes: Iq, Message or Presence. While creating a new Packet instance JIDs are parsed and processed through the stringprep. Hence some of the factory methods may throw TigaseStringprepException exception. You can avoid this by using the methods which accept preparsed JIDs. Reusing preparsed JIDs is highly recommended. 

There are 3 kinds of addresses available from the Packet object: PacketFrom/To, StanzaFrom/To and From/To.
Stanza addresses are the normal XMPP addresses parsed from the XML stanza and as a convenience are available through methods as JID objects. This is not only convenient to the developer but also this is important for performance reasons as parsing JID and processing it through stringprep is quite expensive operation so it is better to do it once and reuse the parsed objects. Please note that any of them can be null. Note also. You should avoid parsing stanza JIDs from the XML element in your code as this may impact the server performance. Reuse the JIDs provided from the Packet methods.
//1.xmpp 报文的jid,

Packet addresses are also JID objects but they may contain a different values from the Stanza addresses. These are the Tigase internal addresses used by the server and they usually contain Tigase component source and destination address. In most cases they are used between connection managers and session managers and can be ignored by other code. One advantage of setting PacketFrom address to address of your component (getComponentId()) address is that if there is a packet delivery problem it will be returned back to the sender with apropriate error message.

Simple From/To addresses contains values following the logic: If PacketFrom/To is not null then it contains PacketFrom/To values otherwise it contains StanzaFrom/To values. This is because the Tigase server tries always to deliver and process the Packet using PacketFrom/To addresses if they are null then Stanza addresses are used instead. So these are just convenience methods which allow avoiding extra IFs in the program code and also save some CPU cycles. Created: Tue Nov 22 07:07:11 2005
//3.如果PacketFrom/To不为空,就是PacketFrom/To;否则就是xmpp stanza的地址;目的是减少程序if else判断

标签: xmpp tigase im
  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 91
博文 108
码字总数 44266
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
* 支付类型