IntroToFramework(xmpp官方)

这是官方文档,暂时没有时间翻译,非常经典,可以看一下

Introduction

  • Quick Note: This document serves to explain the architecture of the XMPPFramework. It assumes a minimal working knowledge of the xmpp protocol.

The framework is divided into 2 parts:

* 1,The xmpp core
* 2,The extensions (roster, XEP's, optional supporting utilities, etc)

The xmpp core is the implementation of the xmpp specification (RFC 3920).

  • Please do not confuse xmpp with chat. XMPP stands for "eXtensible Messaging and Presence Protocol". It is a generic protocol that can be used for many purposes. In fact, there are companies currently using this framework for things such as home automation and delivering code blue alarms to nurses in a hospital.

The extensions include things such as roster support, automatic reconnect, and various implementations of xmpp extensions (XEP's).

XMPP Core {#core}

The core files of the XMPP Framework are located in the folder named "Core". The files include:

  • XMPPStream
  • XMPPParser
  • XMPPJID
  • XMPPElement
  • XMPPIQ
  • XMPPMessage
  • XMPPPresence
  • XMPPModule
  • XMPPLogging
  • XMPPInternal

The heart of the framework is the XMPPStream class. This is the primary class you will be interacting with, and it is the class that all extensions and custom code will plug into. It has a number of interesting features designed to make the framework flexible, extensible, and easy to develop on top of. These will be discussed in more depth later in this document.

The XMPPParser is an internal class used by XMPPStream. You can probably take a wild guess as to what it does. You will not need to interact with the parser in any way, shape, or form.

XMPPJID provides an immutable JID (Jabber Identifier) implementation. It supports parsing of JID's, and extracting various parts of the JID in various forms. It conforms to the NSCopying protocol so that JID's may be used as keys in NSDictionary. It even conforms to the NSCoding protocol.

XMPPElement is the base class for the 3 primary XMPP elements: XMPPIQ, XMPPMessage & XMPPPresence. XMPPElement extends NSXMLElement, so you have the entire NSXML foundation with which to inspect any xml element. This is discussed in more detail in the section Elements: IQ, Message, & Presence.

XMPPModule provides the foundation class for optional pluggable extensions. If you are writing your own application specific (proprietary) code, you will likely just create your own class and register to receive delegate invocations. However, if you are implementing a standard XEP, or you want your application specific extensions to be pluggable, then you'll be building atop XMPPModule. Modules are discussed in more detail below.

XMPPLogging provides a very fast, powerful and flexible logging framework. It is discussed in the XMPP Logging section.

XMPPInternal is just internal stuff related to the core and various advanced low-level extensions.

Elements: IQ, Message, & Presence

XMPPElement extends NSXMLElement, so you have the entire NSXML foundation with which to inspect any xml element.

  • XMPPIQ -> XMPPElement -> NSXMLElement -> NSXMLNode -> NSObject
  • XMPPMessage -> XMPPElement -> NSXMLElement -> NSXMLNode -> NSObject
  • XMPPPresence -> XMPPElement -> NSXMLElement -> NSXMLNode -> NSObject

In addition to the NSXML foundation, there is a NSXMLElement+XMPP category provided by the framework. This category provides various convenient methods to make your code more concise and readable. For example:

[element attributeIntValueForName:@"age"];

For more information, please see the Working With Elements page.

XMPPStream Configuration {#configuration}

The configuration of an xmpp stream instance can be divided into multiple parts:

  • Configuring how to connect to the xmpp server
  • Adding delegates
  • Adding modules
  • Connecting
  • Authenticating

Configuring the connection

For most people, this involves only a single step - set the myJID property of the stream. For example:

xmppStream.myJID = [XMPPJID jidWithString:@"user@gmail.com"];

The xmpp stream will figure out the rest by following the XMPP RFC. This involves doing an SRV lookup for _xmpp-client._tcp.domain. In the example above, using gmail, the google servers will likely return something like "talk.google.com", and the xmpp stream will then connect to that server. If the SRV lookup fails, then the xmpp stream will simply connect to the JID's domain.

If you know you are connecting to an xmpp server that doesn't have xmpp SRV records, you can tell the xmpp stream to skip the SRV lookup by specifying the hostName. For example:

xmppStream.myJID = [XMPPJID jidWithString:@"user@myCompany.com"];
xmppStream.hostName = @"myCompany.com";

The hostname also comes in handy when you're using a development xmpp server. Perhaps the server is only available on the local network, or doesn't have a DNS address, etc. For example:

xmppStream.myJID = [XMPPJID jidWithString:@"user@dev1.myCompany.com"];
xmppStream.hostName = @"192.168.2.27";

Another optional property is the hostPort. By default, and as per the xmpp specifications, almost all servers run on port 5222. However, if your server is running on a different port, you can set the hostPort property.

Adding Delegates

XMPPStream has a number of interesting features designed to make the framework flexible, extensible, and easy to develop on top of. One of which is the use of a MulticastDelegate.

What is a MulticastDelegate?

The xmpp framework needs to support an unlimited number of extensions. This includes the official extensions that ship with the framework, as well as any number of extensions or custom code you may want to plug into the framework. So the traditional delegate pattern simply won't work. XMPP modules and extensions need to be separated into their own separate classes, yet each of these classes needs to receive delegate methods. And the standard NSNotification architecture won't work either because some of these delegates require a return variable. (Plus it's really annoying to extract parameters from a notification's userInfo dictionary.)

So a MulticastDelegate allows you to plug into the framework using the standard delegate paradigm, but it allows multiple classes to receive the same delegate notifications. The beauty of this is that you don't have to put all your xmpp handling code in a single class. You can separate your handling into multiple classes, or however you see fit.

You can add / remove yourself as a delegate of the XMPPStream at any time:

[xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
...
[xmppStream removeDelegate:self];

A more detailed discusion of MulticastDelegate can be found here. A more detailed discussion of threading and queues can be found here.

Adding Modules

There are a number of extensions that ship with the framework, and of course, you can write as many extensions as you wish. We won't review all available extensions, but we'll list a few here for example purposes.

  • XMPPReconnect - automatically reconnects the stream if you get accidentally disconnected.
  • XMPPRoster - provides support for standard xmpp roster.
  • XMPPRoom - provides multi-user chat support.
  • XMPPPubSub - Publish subscribe

As an example, we'll plug-in the XMPPReconnect module to our stream:

xmppReconnect = [ [XMPPReconnect alloc] init];

// Optional configuration of xmppReconnect could go here.
// The defaults are fine for our purposes.

[xmppReconnect activate:xmppStream];

// You can also optionally add delegates to the module.

[xmppReconnect addDelegate:self delegateQueue:dispatch_get_main_queue()];

// And that's all that is needed.
// The module will receive any delegate methods it needs automatically
// from the xmpp stream, and will continue to do its thing unless you deactivate it.

Connecting

When you're ready, you can start the connection process:

NSError *error = nil;
if (![xmppStream connect:&error])
{
    NSLog(@"Oops, I probably forgot something: %@", error);
}

If you forgot to set a required property, such as myJID, then the connect method will return NO, and the error message will inform you of the problem.

During the connection process, the client and server go through a xmpp handshake. During this time, the server informs the client of various protocols that it supports as well as any that it requires. Some servers may require the connection be secured via SSL/TLS (startTLS). If this is the case, the xmpp stream will automatically secure the connection. If you're connecting to a server with an improper X509 certificate, you may need to implement the xmppStream:willSecureWithSettings: delegate method to alter the default security settings.

Authenticating

After all the connection handshaking has completed, the xmppStreamDidConnect: delegate method is invoked. This is generally where most clients should start the authentication process. This is as simple as:

- (void)xmppStreamDidConnect:(XMPPStream *)sender
{
    [xmppStream authenticateWithPassword:password error:NULL];
}

XMPP Logging

There were several goals for logging throughout the xmpp framework:

  • It must support several log levels.

    • Not all log messages have the same priority. Some are about errors, while others are just informational. Levels help developers keep their log messages intact, with the ability to turn them on and off without any difficulty.
  • It must be configurable on a per-file basis.

    • A global log level doesn't cut it when the framework consists of so many files. Plus debugging an issue often means developers only want to see log statements from a few files.
  • It must be configurable to the end user.

  • Users of the xmpp framework need full control over what ultimately happens concerning the log statements. And users have very different needs. Some want log statements to go to a file. Others may want log statements to go to a database. Or maybe they need to direct log statements to different places depending on whether the log statement is coming from their app or the xmpp framework.

I have worked with many clients over the years, and I see the same problem concerning 3rd party frameworks occurring over and over again. The 3rd party library comes scattered with NSLog statements, which ultimately require the user to go through the library commenting out the NSLog statements, or converting them to some primitive custom macro version.

So rather than whip up yet another primitive macro that ultimately uses the same stupid NSLog, the xmpp framework uses a professional logging framework: CocoaLumberjack. This logging framework is actually faster than NSLog, even when doing the exact same thing. In addition it supports a ton of different configurations, and allows end users to even add their own custom loggers and/or filters and/or formatters. For more information there is a massive amount of documentation available via the Lumberjack Wiki.

Here's what you need to know concerning how logging is setup for XMPPFramework:

Towards the top of most files within the framework you'll find the following

// Log levels: off, error, warn, info, verbose
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN;

As you can see, there are 4 log levels (plus XMPP_LOG_LEVEL_NONE):

  • Error
  • arning
  • Info
  • Verbose

You can change the log level of any file to have it spit out more information.

In addition to this, there is a Trace flag that can be enabled. When tracing is enabled, it spits out the methods that are being called.

Please note that tracing is separate from the log levels. For example, one could set the log level to warning, and enable tracing like this

// Log levels: off, error, warn, info, verbose
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN | XMPP_LOG_FLAG_TRACE;

In terms of code, this means

XMPPLogTrace(); // Enabled - Will spit out "<FileName>: <MethodName>"
XMPPLogError(@"I will get logged");
XMPPLogWarn(@"I will get logged");
XMPPLogInfo(@"I will NOT get logged");
XMPPLogVerbose(@"I will NOT get logged");

In addition to this, XMPPStream has an option which enables you to see the raw XML that is being sent / received. You can turn it on in XMPPStream.m like so:

// Log levels: off, error, warn, info, verbose
static const int xmppLogLevel = XMPP_LOG_LEVEL_INFO | XMPP_LOG_FLAG_SEND_RECV;

Recall that the goal of all this logging is to put YOU in control of what gets logged and where those log statements go. This means that you'll need to configure the lumberjack framework when your application starts up. For starters, you can do something as simple as this in your AppDelegate:

#import "DDLog.h"
#import "DDTTYLogger.h"

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    [DDLog addLogger:[DDTTYLogger sharedInstance] withLogLevel:XMPP_LOG_FLAG_SEND_RECV];

    // All your other code...
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容