xcode 无法创建 xmpp muc 房间:代码 503(服务不可用)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11791022/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 01:07:54  来源:igfitidea点击:

Trouble creating xmpp muc room: Code 503 (service unavailable)

iosxcodeios5xmppxmppframework

提问by user1561639

My code to create a room:

我创建房间的代码:

XMPPRoomCoreDataStorage *rosterstorage = [[XMPPRoomCoreDataStorage alloc] init];
XMPPRoom *xmppRoom = [[XMPPRoom alloc] initWithRoomStorage:rosterstorage jid:[XMPPJID jidWithString:@"[email protected]/groupchat"] dispatchQueue:dispatch_get_main_queue()];

[xmppRoom activate:[[self appDelegate] xmppStream]];
if ([xmppRoom preJoinWithNickname:@"nameToCreateRoom"]) 
{
    NSLog(@"room created");
    [xmppRoom joinRoomUsingNickname:self.userName history:nil];
}
[xmppRoom fetchConfigurationForm];
[xmppRoom configureRoomUsingOptions:nil];
[xmppRoom addDelegate:[self appDelegate] delegateQueue:dispatch_get_main_queue()];

Debug:

调试:

2012-08-03 07:46:29.204 iPhoneXMPP[9887:fb03] room created
2012-08-03 07:46:29:230 iPhoneXMPP[9887:15003] SEND: <iq type="get" to="[email protected]" id="B793062B-0E09-492F-BC0F-703503AAA664"><query xmlns="http://jabber.org/protocol/muc#owner"/></iq>
2012-08-03 07:46:29:237 iPhoneXMPP[9887:15003] SEND: <iq type="set" to="[email protected]" id="392D5BFC-707B-4F68-A829-56F949F4E96D"><query xmlns="http://jabber.org/protocol/muc#owner"><x xmlns="jabber:x:data" type="submit"/></query></iq>
2012-08-03 07:46:29:326 iPhoneXMPP[9887:14f03] SEND: <presence to="[email protected]"><x xmlns="http://jabber.org/protocol/muc"/><x xmlns="vcard-temp:x:update"><photo>91217a961321f8f6380ea2feefd0632353ad296c</photo></x><c xmlns="http://jabber.org/protocol/caps" hash="sha-1" node="http://code.google.com/p/xmppframework" ver="VyOFcFX6+YNmKssVXSBKGFP0BS4="/></presence>
2012-08-03 07:46:29:327 iPhoneXMPP[9887:14f03] RECV: <iq xmlns="jabber:client" from="[email protected]" to="[email protected]/41068195801343976386548353" type="error" id="B793062B-0E09-492F-BC0F-703503AAA664"><query xmlns="http://jabber.org/protocol/muc#owner"/><error code="503" type="cancel"><service-unavailable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error></iq>
2012-08-03 07:46:29:343 iPhoneXMPP[9887:fb03] iPhoneXMPPAppDelegate: xmppStream:didReceiveIQ:
2012-08-03 07:46:29:421 iPhoneXMPP[9887:15003] RECV: <iq xmlns="jabber:client" from="[email protected]" to="[email protected]/41068195801343976386548353" type="error" id="392D5BFC-707B-4F68-A829-56F949F4E96D"><query xmlns="http://jabber.org/protocol/muc#owner"><x xmlns="jabber:x:data" type="submit"/></query><error code="503" type="cancel"><service-unavailable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error></iq>
2012-08-03 07:46:29:440 iPhoneXMPP[9887:fb03] iPhoneXMPPAppDelegate: xmppStream:didReceiveIQ:

I see that it is creating/joining [email protected] and not [email protected]/groupchat like I specified. I read that this is most likely the problem. However, I have specified for the full jid, so I'm lost.

我看到它正在创建/加入 [email protected] 而不是我指定的 [email protected]/groupchat。我读到这很可能是问题所在。但是,我已经指定了完整的 jid,所以我迷路了。

Thanks in advance to all who help.

在此先感谢所有帮助的人。

回答by Sihad Begovic

First, take look here XEP-0045: Multi-User Chat.
As you can see, first you have to discover which capabilities your user (XMPPJID) has on the Jabber server.

To do this, send next command to your Jabber Server:

首先,看看这里XEP-0045:多用户聊天
如您所见,首先您必须发现您的用户 (XMPPJID) 在 Jabber 服务器上具有哪些功能。

为此,请将下一个命令发送到您的 Jabber 服务器:

<iq from='[email protected]/resource' id='some_expression' to='jabber.server.com' type='get'>
    <query xmlns='http://jabber.org/protocol/disco#items'/>
</iq>

or writen in objective-c using XMPP library functions:

或使用 XMPP 库函数在 Objective-c 中编写:

NSError *error = nil;
NSXMLElement *query = [[NSXMLElement alloc] initWithXMLString:@"<query xmlns='http://jabber.org/protocol/disco#items'/>" 
                                                        error:&error];
XMPPIQ *iq = [XMPPIQ iqWithType:@"get" 
                             to:[XMPPJID jidWithString:@"jabber.server.com"] 
                      elementID:[xmppStream generateUUID] child:query];
[xmppStream sendElement:iq];

Now listen response from server in XMPPStream delegate - (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iqand server response should be something like this:

现在在 XMPPStream 委托中监听来自服务器的响应- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq,服务器响应应该是这样的:

<iq from='jabber.server.com' id='some_expression' to='[email protected]/resource' type='result'>
    <query xmlns='http://jabber.org/protocol/disco#items'>
        <item jid='im.jabber.server.com' name='Instant Message Service'/>
        <item jid='conference.jabber.server.com' name='Chatroom Service'/>
    </query>
</iq>

or objective c:

或目标 c:

- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{

    if([iq isResultIQ])
    {
        if([iq elementForName:@"query" xmlns:@"http://jabber.org/protocol/disco#items"])
        {
            NSLog(@"Jabber Server's Capabilities: %@", [iq XMLString]);
        }
    }
}

Now for every item returned send IQ to your server for it's properties and figure out which one is type of conference, something like this:

现在,对于返回的每个项目,将 IQ 发送到您的服务器以获取其属性,并确定哪个是会议类型,如下所示:

<iq from='[email protected]/resource' id='some_expression' to='conference.jabber.server.com' type='get'>
    <query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>

or in objective c:

或在目标 c 中:

- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{

    if([iq isResultIQ])
    {
        if([iq elementForName:@"query" xmlns:@"http://jabber.org/protocol/disco#items"])
        {
            NSXMLElement *query = [iq childElement];
            NSArray *items = [query children];
            for(NSXMLElement *item in items)
            {
                NSError *error = nil;
                NSXMLElement *sendQuery = [[NSXMLElement alloc] initWithXMLString:@"<query xmlns='http://jabber.org/protocol/disco#info'/>" 
                                                                            error:&error];
                XMPPIQ *sendIQ = [XMPPIQ iqWithType:@"get" 
                                                 to:[XMPPJID jidWithString:[item attributeStringValueForName:@"jid"]] 
                                          elementID:[xmppStream generateUUID] 
                                              child:sendQuery];
                [xmppStream sendElement:sendIQ];
            }
        }
    }
}

Listen for responses from server:

监听来自服务器的响应:

<iq from='conference.jabber.server.com' id='some_expression' to='[email protected]/resource' type='result'>
    <query xmlns='http://jabber.org/protocol/disco#info'>
        <identity category='conference' name='Server Group Chat Service' type='text'/>
        <feature var='http://jabber.org/protocol/muc'/>
    </query>
</iq>

and take group chat domain from identity with category:conference

并从身份中获取群聊域 category:conference

- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{

    if([iq isResultIQ])
    {
        if([iq elementForName:@"query" xmlns:@"http://jabber.org/protocol/disco#items"])
        {
            ...
        }
        else if([iq elementForName:@"query" xmlns:@"http://jabber.org/protocol/disco#info"])
        {
            NSXMLElement *query = [iq childElement];
            NSXMLElement *identity = [query elementForName:@"identity"];
            if([[identity attributeStringValueForName:@"category"] isEqualToString:@"conference"])
            {
                groupChatDomain = [iq fromStr];
            }
        }
    }
}

Finally, when we got group chat domain we can create chat room something like this:

最后,当我们获得群聊域时,我们可以创建这样的聊天室:

XMPPJID *chatRoomJID = [XMPPJID jidWithUser:@"chat_room" 
                                     domain:groupChatDomain 
                                   resource:@"user"];
XMPPRoomMemoryStorage *roomMemoryStorage = [[XMPPRoomMemoryStorage alloc] init];
XMPPRoom *xmppRoom = [[XMPPRoom alloc] initWithRoomStorage:roomMemoryStorage
                                                       jid:roomChatJID
                                             dispatchQueue:dispatch_get_main_queue()];
[xmppRoom activate:xmppStream];
[xmppRoom addDelegate:self delegateQueue:dispatch_get_main_queue()];
[xmppRoom joinRoomUsingNickname:user history:nil];

and add <XMPPRoomDelegate>protocol in your view controller and its delegates:

<XMPPRoomDelegate>在您的视图控制器及其委托中添加协议:

- (void)xmppRoomDidCreate:(XMPPRoom *)sender
- (void)xmppRoomDidDestroy:(XMPPRoom *)sender
- (void)xmppRoom:(XMPPRoom *)sender didConfigure:(XMPPIQ *)iqResult
- (void)xmppRoom:(XMPPRoom *)sender didNotConfigure:(XMPPIQ *)iqResult
- (void)xmppRoomDidJoin:(XMPPRoom *)sender
- (void)xmppRoomDidLeave:(XMPPRoom *)sender
- (void)xmppRoom:(XMPPRoom *)sender occupantDidJoin:(XMPPJID *)occupantJID withPresence:(XMPPPresence *)presence
- (void)xmppRoom:(XMPPRoom *)sender occupantDidLeave:(XMPPJID *)occupantJID withPresence:(XMPPPresence *)presence
- (void)xmppRoom:(XMPPRoom *)sender didReceiveMessage:(XMPPMessage *)message fromOccupant:(XMPPJID *)occupantJID

Note:Before inviting other users to Chat Room, you have to send and confirm room configurations (other users can be invited but messages can not be sent).
So you can do this after Room is created (delegate - (void)xmppRoomDidCreate:(XMPPRoom *)senderis called) or your user has joined (delegate - (void)xmppRoomDidJoin:(XMPPRoom *)senderis called) to Chat Room.

To send and confirm room configuration do one of the following:

注意:在邀请其他用户加入聊天室之前,您必须发送并确认房间配置(可以邀请其他用户但不能发送消息)。
因此,您可以在创建聊天室- (void)xmppRoomDidCreate:(XMPPRoom *)sender- (void)xmppRoomDidJoin:(XMPPRoom *)sender调用委托)或您的用户加入(调用委托)聊天室之后执行此操作。

要发送和确认房间配置,请执行以下操作之一:

- (void)xmppRoomDidCreate:(XMPPRoom *)sender
{
    [sender configureRoomUsingOptions:nil];
}

or

或者

- (void)xmppRoomDidJoin:(XMPPRoom *)sender
{    
    [sender configureRoomUsingOptions:nil];
}

Send nilto accept default options or you can send IQ with syntax as below to your server:

发送nil以接受默认选项,或者您可以使用以下语法将 IQ 发送到您的服务器:

<iq type='set' from='[email protected]/resource' id='some_expression' to='[email protected]'>
    <query xmlns='http://jabber.org/protocol/muc#owner'>
        <x xmlns='jabber:x:data' type='submit'>
            <field var='FORM_TYPE'>
                <value>http://jabber.org/protocol/muc#roomconfig</value>
            </field>
            <field var='muc#roomconfig_roomname'>
                <value>My Chat Room</value>
            </field>
              .
              .
              .
        <x>
</query>
</iq>

or objective c code:

或目标c代码:

NSError *error = nil;
NSXMLElement *query = [[NSXMLElement alloc] initWithXMLString:@"<query xmlns='http://jabber.org/protocol/muc#owner'/>" 
                                                        error:&error];
NSXMLElement *x = [NSXMLElement elementWithName:@"x" 
                                          xmlns:@"jabber:x:data"];
[x addAttributeWithName:@"type" stringValue:@"submit"];
NSXMLElement *field1 = [NSXMLElement elementWithName:@"field"];
[field1 addAttributeWithName:@"var" stringValue:@"FORM_TYPE"];
NSXMLElement *value1 = [NSXMLElement elementWithName:@"value" 
                                         stringValue:@"http://jabber.org/protocol/muc#roomconfig"];
[field1 addChild:value1];

NSXMLElement *field2 = [NSXMLElement elementWithName:@"field"];
[field2 addAttributeWithName:@"var" stringValue:@"muc#roomconfig_roomname"];
NSXMLElement *value2 = [NSXMLElement elementWithName:@"value" 
                                         stringValue:@"My Chat Room"];
[field2 addChild:value2];

//Add other fields you need, just like field1 and field2

[x addChild:field1];
[x addChild:field2];

[query addChild:x];

NSXMLElement *roomOptions = [NSXMLElement elementWithName:@"iq"];
[roomOptions addAttributeWithName:@"type" stringValue:@"set"];
[roomOptions addAttributeWithName:@"id" stringValue:[xmppStream generateUUID];
[roomOptions addAttributeWithName:@"to" stringValue:@"[email protected]"];

[roomOptions addChild:query];

[sender configureRoomUsingOptions:roomOptions];

and list of all possible Configuration Form fields is here

所有可能的配置表单字段的列表在这里