zoukankan      html  css  js  c++  java
  • XMPP 基于XML的点对点通信协议

    XMPP 基于XML的点对点通信协议

     

    IM: 即时通信

    XMPP: 基于XML的点对点通信协议

    1. ejabber: 这个软件是用来开启本地服务器使用, 本地服务器地址为: 127.0.0.1, 所有的电脑都一样, 开启服务器的软件有很多

    2. Audium: 就是一个聊天工具

    用局域网聊天

    1.在同一个WIFI

    2.在同一个本地服务器创建账号

    3.登陆的时候, 设置好服务器地址, 为电脑的IP地址

    XAMPP: 集成了阿帕奇 FTPMy SQL的一个软件

    类的扩展有三种方式

    1.协议: 需要自己制定协议, 设置代理, 遵守协议, 一般用来传值(回调)

    2.延展: 为类添加私有方法和私有变量, 一般用于已知类(.h.m都存在的类)

    3.类目: 为类添加方法和属性(只有settergetter, 没有实例变量), 必须实现内部声明的方法, 一般用于系统类的扩展

    XMPP的安装

    XMPP安装需要的软件

        

    安装ejabberd

    选择ejabberd.app进行安装

    用户名和密码填写完要记住,之后会用到

    安装成功后,在Finder->应用程序->ejabberd-14.07->bin->start点击start.exec运行,会跳出一个网页

    在网页上可以添加账号和密码

     

    将 软件添加到Finder->应用程序中,点击打开app,可以用ejabberd中注册的账号和密码登陆

    详细代码:

    在工程中添加框架和MI类 

    storyboard基本布局: 

    ViewController.m
    #import "ViewController.h"
    //引入头文件
    #import "XMPPFramework.h"
    #import "XMPPManager.h"
    #import "ContactViewController.h"
    #define JID(USER_NAME) [NSString stringWithFormat:@"%@@bogon", USER_NAME]
    @interface ViewController ()<XMPPStreamDelegate, UIAlertViewDelegate, XMPPRosterDelegate>
    @property (weak, nonatomic) IBOutlet UITextField *userNameTF;
    @property (weak, nonatomic) IBOutlet UITextField *passwordTF;
    //花名册
    @property (nonatomic, strong) XMPPRoster *roster;
    //花名册数组
    @property (nonatomic, strong) NSMutableArray *rosterArr;
    - (IBAction)loginClick:(id)sender;
    //创建XMPPStream类的属性
    @property (nonatomic, strong) XMPPStream *stream;
    @end
    
    @implementation ViewController
    
    //点击页面代理方法
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        //结束编辑状态
        [self.view endEditing:YES];
    }
    
    //重写XMPPStream的getter方法
    - (XMPPStream *)stream {
        if (_stream == nil) {
            self.stream = [[XMPPStream alloc] init];
            _stream.hostName = @"127.0.0.1";
            _stream.hostPort = 5222;
            [_stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
            //激活花名册
            [self.roster activate:_stream];
        }
        return _stream;
    }
    
    //重写XMPPRoster花名册方法
    - (XMPPRoster *)roster {
        if (!_roster) {
            self.roster = [[XMPPRoster alloc] initWithRosterStorage:[XMPPRosterCoreDataStorage sharedInstance] dispatchQueue:dispatch_get_main_queue()];
            //配置参数
            [_roster addDelegate:self delegateQueue:dispatch_get_main_queue()];
        }
        return _roster;
    }
    
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        //记录stream
        [XMPPManager sharedManager].stream = self.stream;
        
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    //登陆按钮
    - (IBAction)loginClick:(id)sender {
        //登陆
        //1.断开连接
        [self.stream disconnect];
        //2.设置JID:设置字符串宏
        self.stream.myJID = [XMPPJID jidWithString: JID(self.userNameTF.text)];
        //3.连接服务器
        [self.stream connectWithTimeout:-1 error:nil];
    }
    
    #pragma mark-XMPPStreamDelegate
    //连接服务器成功
    - (void)xmppStreamDidConnect:(XMPPStream *)sender {
        //连接服务器成功以后登陆
        [self.stream authenticateWithPassword:self.passwordTF.text error:nil];
    }
    
    //连接服务器超时
    - (void)xmppStreamConnectDidTimeout:(XMPPStream *)sender {
          NSLog(@"连接超时");
    }
    
    //登陆成功
    - (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {
        //发送登陆成功状态
        XMPPPresence *presence = [XMPPPresence presence];
        [self.stream sendElement:presence];
        //记录当前登陆的JID
        [[NSUserDefaults standardUserDefaults] setObject:[NSString stringWithFormat:@"%@@bogon", self.userNameTF.text] forKey:@"MyJID"];
        [[[UIAlertView alloc] initWithTitle:@"登陆成功" message:@"" delegate:self cancelButtonTitle:@"好的" otherButtonTitles: nil] show];
    }
    
    //登录失败
    - (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error {
          [[[UIAlertView alloc] initWithTitle:@"登陆失败" message:@"" delegate:self cancelButtonTitle:@"好的" otherButtonTitles: nil] show];
    }
    
    //接收到消息的代理方法
    - (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {
        //如果body的长度为空
        if (message.body.length == 0) {
            
        } else {
            NSLog(@"message: %@", message);
        }
    }
    
    
    #pragma mark - UIAlertViewDelegate
    - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
        NSLog(@"%ld", buttonIndex);
        if (buttonIndex == 0) {
            //触发sugue
            [self performSegueWithIdentifier:@"modelToContact" sender:nil];
        } else {
            //清空密码输入框
            self.passwordTF.text = @"";
        }
    }
    
    #pragma mark-XMPPRosterDelegate
    - (void)xmppRosterDidBeginPopulating:(XMPPRoster *)sender {
        NSLog(@"开始获取花名册");
        self.rosterArr = [@[] mutableCopy];
    }
    
    - (void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DDXMLElement *)item {
        NSLog(@"获取花名册中");
        [self.rosterArr addObject:item];
    }
    
    - (void)xmppRosterDidEndPopulating:(XMPPRoster *)sender {
        NSLog(@"结束获取");
        NSLog(@"rosterArr: %@", self.rosterArr);
    }
    
    //属性传值
    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
        if ([segue.identifier isEqualToString:@"modelToContact"]) {
            ContactViewController *contact = segue.destinationViewController;
            contact.temArr = self.rosterArr;
        }
    }
    @end
    ContactViewController.m
    #import "ContactViewController.h"
    #import "DDXMLElement.h"
    #import "ChatViewController.h"
    
    @interface ContactViewController ()<UITableViewDataSource, UITableViewDelegate>
    - (IBAction)back:(id)sender;
    @property (weak, nonatomic) IBOutlet UITableView *tableView;
    
    @end
    
    @implementation ContactViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    #pragma mark-UITableViewDataSource
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        return self.temArr.count;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
        
        DDXMLElement *friendItem = self.temArr[indexPath.row];
        //找到 JID 字符串
        NSString *jidString = [[friendItem attributeForName:@"jid"] stringValue];
        cell.textLabel.text = jidString;
        return cell;
    }
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        [self performSegueWithIdentifier:@"modelToChat" sender:indexPath];
    }
    
    
    #pragma mark - Navigation
    
    // In a storyboard-based application, you will often want to do a little preparation before navigation
    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
        if ([segue.identifier isEqualToString:@"modelToChat"]) {
            ChatViewController *chatVC = segue.destinationViewController;
            NSIndexPath *index = (NSIndexPath *)sender;
            chatVC.friendJID = [[self.temArr[index.row] attributeForName:@"jid"] stringValue];
        }
    }
    
    
    - (IBAction)back:(id)sender {
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    @end
    ContactViewController.h
    #import <UIKit/UIKit.h>
    
    @interface ContactViewController : UIViewController
    @property (nonatomic, strong) NSMutableArray *temArr;
    @end
    ChatViewController.h
    #import <UIKit/UIKit.h>
    
    @interface ChatViewController : UIViewController
    @property (nonatomic, copy)NSString *friendJID;
    @end
    ChatViewController.m
    #import "ChatViewController.h"
    #import "XMPPFramework.h"
    #import "XMPPManager.h"
    
    @interface ChatViewController ()<UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate, XMPPStreamDelegate>
    - (IBAction)back:(id)sender;
    @property (weak, nonatomic) IBOutlet UITableView *tableView;
    @property (weak, nonatomic) IBOutlet UITextField *textField;
    
    @end
    
    @implementation ChatViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    #pragma mark-UITableViewDataSource
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        return 10;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
        cell.textLabel.text = @"123";
        return cell;
    }
    
    #pragma mark-XMPPStreamDelegate
    - (void)xmppStreamDidConnect:(XMPPStream *)sender {
        NSLog(@"连接服务器成功");
    }
    
    - (void)xmppStreamConnectDidTimeout:(XMPPStream *)sender {
        NSLog(@"连接服务器超时");
    }
    
    - (void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message {
        NSLog(@"发送成功");
    }
    
    - (void)xmppStream:(XMPPStream *)sender didFailToSendMessage:(XMPPMessage *)message error:(NSError *)error {
        NSLog(@"消息发送失败%@", error);
    }
    
    /*
    #pragma mark - Navigation
    
    // In a storyboard-based application, you will often want to do a little preparation before navigation
    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
        // Get the new view controller using [segue destinationViewController].
        // Pass the selected object to the new view controller.
    }
    */
    
    - (IBAction)back:(id)sender {
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    
    #pragma mark-UITextFieldDelegate
    //点击return按钮事件
    - (BOOL)textFieldShouldReturn:(UITextField *)textField {
        //创建消息体
        XMPPMessage *message = [XMPPMessage messageWithType:@"text" to:[XMPPJID jidWithString:self.friendJID]];
        //添加消息内容
        [message addBody:textField.text];
        //发送消息
        [[XMPPManager sharedManager].stream sendElement:message];
        //收回键盘
        [textField resignFirstResponder];
        return YES;
    }
    
    @end
    XMPPManager.h
    #import <Foundation/Foundation.h>
    
    @interface XMPPManager : NSObject
    + (XMPPManager *)sharedManager;
    @property (nonatomic, strong) id stream;
    @end
    XMPPManager.m
    #import "XMPPManager.h"
    
    @implementation XMPPManager
    + (XMPPManager *)sharedManager {
        static XMPPManager *manager = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            manager = [self new];
        });
        return manager;
    }
    @end
    NSString+JID.h
    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    @interface UITextField (JID)
    @property (nonatomic, copy) NSString *jid;
    @end
    NSString+JID.m
    #import "NSString+JID.h"
    
    @implementation UITextField (JID)
    
    - (void)setJid:(UITextField *)jid {
        
    }
    
    - (NSString *)jid {
        return [NSString stringWithFormat:@"%@@bogon", self.text];
    }
    
    @end
    RegisterViewController.m
    #import "RegisterViewController.h"
    //引入 XMPP 框架的头文件
    #import "XMPPFramework.h"
    @interface RegisterViewController ()<XMPPStreamDelegate>
    @property (weak, nonatomic) IBOutlet UITextField *userNameTF;
    @property (weak, nonatomic) IBOutlet UITextField *passwordTF;
    - (IBAction)registerClick:(id)sender;
    - (IBAction)goBack:(id)sender;
    //创建一个 XMPPStream类的属性
    @property (nonatomic, strong) XMPPStream *stream;
    
    @end
    
    @implementation RegisterViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        //初始化 XMPPStream
        self.stream = [[XMPPStream alloc] init];
        //设置服务器地址
        _stream.hostName = @"127.0.0.1";
        //设置服务器的端口号
        _stream.hostPort = 5222;
        //设置XMPPStream代理
        [_stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
    
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    /*
    #pragma mark - Navigation
    
    // In a storyboard-based application, you will often want to do a little preparation before navigation
    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
        // Get the new view controller using [segue destinationViewController].
        // Pass the selected object to the new view controller.
    }
    */
    
    - (IBAction)registerClick:(id)sender {
        //设置 JID
        //JID是用户在聊天服务器中的唯一标识
        //JID 有两部分构成: 用户名@域名
        self.stream.myJID = [XMPPJID jidWithString:[NSString stringWithFormat:@"%@@bogon", self.userNameTF.text]];
        //注册
        //1. 连接服务器
        //先断开连接
        [self.stream disconnect];
        //-1 代表无限大, 直到连接上服务器
        [self.stream connectWithTimeout:-1 error:nil];
    }
    
    - (IBAction)goBack:(id)sender {
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    
    #pragma mark-XMPPStreamDelegate
    //连接服务器超时
    - (void)xmppStreamConnectDidTimeout:(XMPPStream *)sender {
        NSLog(@"%s", __FUNCTION__);
    }
    
    //连接服务器成功
    - (void)xmppStreamDidConnect:(XMPPStream *)sender {
        NSLog(@"%s", __FUNCTION__);
        //2.连接服务器成功以后进行注册
        [self.stream registerWithPassword:self.passwordTF.text error:nil];
    }
    
    //注册成功
    - (void)xmppStreamDidRegister:(XMPPStream *)sender {
        [[[UIAlertView alloc] initWithTitle:@"恭喜你" message:@"注册成功" delegate:self cancelButtonTitle:nil otherButtonTitles:@"前往登陆", nil] show];
    }
    
    //注册失败
    - (void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error {
        
    }
    
    @end

     

  • 相关阅读:
    终于把5GB的Cygwin安装完成了
    JavaApplet-Application Blocked..Your security setting have blocked an untrusted application from running..
    C++程序运行时间测定
    WAV MP3 Converter-强大的音频转换软件-特别版
    搞ACM的你伤不起[转载] 原作者:RoBa
    邮件中的CC和BCC含义
    MESS-配置
    ShareRepository
    利用DB Link两步搞定Oracle两个数据库间的表同步
    使用ASP .NET (C#) 產生PDF檔的好幫手—iTextSharp library (上)
  • 原文地址:https://www.cnblogs.com/OrangesChen/p/5135129.html
Copyright © 2011-2022 走看看