一、即时通讯
1、简介
即时通讯(Instant Messaging)是目前Internet上最为流行的通讯方式,各种各样的即时通讯软件也层出不穷,服务提供商也提供了越来越丰富的通讯服务功能。
2、实现方式
即时通讯有多种实现方式,例如:XMPP、环信、融云等。
下面我们对XMPP的使用进行介绍。
3、什么是XMPP
XMPP(XML,Messages,Presence,Protocol)是基于可扩展标记语言(XML)的协议,可用于即时通信(IM)。
——可扩展消息处理现场协议。
4、XMPP优点
- 开放:
- XMPP协议是由JSF开源社区组织开发的,不属于任何的机构和个人,从根本上保证了其开放性。
- 标准:
- 互联网工程工作组将XMPP于2002年正式列为认可的实时通讯及Presence技术。
- 分布式的网络架构:
- XMPP 协议虽然是基于Client/Server 架构,但是XMPP协议本身并没有这样的限制。网络的架构和电子邮件十分相似,但没有结合任何特定的网络架构,适用范围非常广泛。
- XMPP 协议具有良好的扩展性:
- 基于XML 建立起来的应用具有良好的语义完整性和扩展性。
- XMPP 具有很好的弹性:
- XMPP 除了可用在即时通信的应用程序,还能用在网络管理、内容供稿、协同工具、档案共享、游戏、远端系统监控等。
- 安全性:
- XMPP在Client-to-Server通信和Server-to-Server通信中都使用TLS (Transport Layer Security)协议作为通信通道的加密方法,保证通信的安全。
二、XMPP实现即时通讯
首先搭建XMPP环境:具体操作请参考我的另一篇博客XMPP环境搭建。
四、工程中添加XMPP
1、创建新工程
2、导入XMPP框架,XMPPFramework:github下载地址。
3、引入XMPP需要的依赖库 libxml libresolv
4、设置路径 /usr/include/libxml2
五、登录、注册
首先用storyboard搭建框架:
具体代码实现:
LoginViewController.m
@interface LoginViewController () /// 用户名 @property (weak, nonatomic) IBOutlet UITextField *userNameTextField; /// 密码 @property (weak, nonatomic) IBOutlet UITextField *passwordTextField; @end @implementation LoginViewController - (void)viewDidLoad { [super viewDidLoad]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } #pragma mark - 登录按钮的响应方法 - (IBAction)loginAction:(id)sender { [[XMPPManager sharedXMPPManager] loginWithUserName:self.userNameTextField.text password:self.passwordTextField.text]; } @end
RegisterViewController.m
@interface RegistViewController ()<XMPPStreamDelegate> /// 注册用户名 @property (weak, nonatomic) IBOutlet UITextField *userNameTextField; /// 注册密码 @property (weak, nonatomic) IBOutlet UITextField *passwordTextField; @end @implementation RegistViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. [[XMPPManager sharedXMPPManager].xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } // 注册按钮的响应方法 - (IBAction)registerAction:(id)sender { [[XMPPManager sharedXMPPManager] registerWithUserName:self.userNameTextField.text password:self.passwordTextField.text]; } #pragma mark - 实现XMPPStreamDelegate协议方法 // 实现协议是为了满足需求:注册成功之后跳转(dismiss)回页面 - (void)xmppStreamDidRegister:(XMPPStream *)sender { NSLog(@"注册成功"); [self dismissViewControllerAnimated:YES completion:nil]; } - (void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error { NSLog(@"注册失败:error = %@", error); } @end
XMPPManager.h
@interface XMPPManager : NSObject /// 声明一个通道的属性 @property (nonatomic, strong) XMPPStream *xmppStream; + (XMPPManager *)sharedXMPPManager; // 登录的方法 - (void)loginWithUserName:(NSString *)userName password:(NSString *)password; // 注册的方法 - (void)registerWithUserName:(NSString *)userName password:(NSString *)password; @end
XMPPManager.m
#import "XMPPManager.h" static XMPPManager *manager = nil; // 记录状态 typedef NS_ENUM(NSUInteger, ConnectToServerPurpose) { ConnectToServerPurposeLogin, ConnectToServerPurposeRegister, }; @interface XMPPManager ()<XMPPStreamDelegate> /// 记录当前状态(登录/注册) @property (nonatomic) ConnectToServerPurpose connectToServer; /// 用户名 @property (nonatomic, strong) NSString *userName; /// 密码 @property (nonatomic, strong) NSString *password; /// 注册的用户名 @property (nonatomic, strong) NSString *registerUserName; /// 注册的密码 @property (nonatomic, strong) NSString *registerPassword; @end @implementation XMPPManager + (XMPPManager *)sharedXMPPManager { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ manager = [[XMPPManager alloc] init]; }); return manager; } #pragma mark - 1.创建通道 - (instancetype)init { self = [super init]; if (self) { // 初始化通道 self.xmppStream = [[XMPPStream alloc] init]; // openfire服务器IP地址 self.xmppStream.hostName = kHostName; // openfire服务器端口 默认5222 self.xmppStream.hostPort = kHostPort; // 添加代理 [self.xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()]; } return self; } #pragma mark - 登录的方法 - (void)loginWithUserName:(NSString *)userName password:(NSString *)password { self.userName = userName; self.password = password; // 记录登录状态 self.connectToServer = ConnectToServerPurposeLogin; // 连接服务器 [self linkServer]; } #pragma mark - 注册的方法 - (void)registerWithUserName:(NSString *)userName password:(NSString *)password { self.registerUserName = userName; self.registerPassword = password; // 记录注册状态 self.connectToServer = ConnectToServerPurposeRegister; // 连接服务器 [self linkServer]; } #pragma mark - 连接服务器 - (void)linkServer { NSString *string = [[NSString alloc] init]; switch (self.connectToServer) { case ConnectToServerPurposeLogin: string = [NSString stringWithFormat:@"%@", self.userName]; break; case ConnectToServerPurposeRegister: string = [NSString stringWithFormat:@"%@", self.registerUserName]; break; default: break; } // 要连接服务器,要有用户身份认证 // 身份证 // 第一个参数:用户名 // 第二个参数:域名 // 第三个参数:资源 XMPPJID *jid = [XMPPJID jidWithUser:string domain:kDomin resource:kResource]; // 通过通道进行身份验证 self.xmppStream.myJID = jid; // 如果当前聊天工具处于连接状态或者已经连接,此时,需要切断连接(此逻辑不唯一,根据需求而定) if ([self.xmppStream isConnected] || [self.xmppStream isConnecting]) { // 切断连接 [self disConnectedToServer]; } // 设置连接超时 NSError *error = nil; [self.xmppStream connectWithTimeout:30 error:&error]; if (error) { NSLog(@"服务器连接超时"); } } #pragma mark - 断开连接 - (void)disConnectedToServer { // 当前用户下线了 XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"]; // 告诉通道下线了 [self.xmppStream sendElement:presence]; // 使通道失去连接 [self.xmppStream disconnect]; } #pragma mark - XMPPStreamDelegate协议方法 // 连接超时 - (void)xmppStreamConnectDidTimeout:(XMPPStream *)sender { NSLog(@"连接超时"); } // 连接成功 - (void)xmppStreamDidConnect:(XMPPStream *)sender { NSLog(@"连接成功"); // 登录密码的验证 // [self.xmppStream authenticateWithPassword:self.password error:nil]; // 区分登录和注册进行密码验证 switch (self.connectToServer) { case ConnectToServerPurposeLogin: [self.xmppStream authenticateWithPassword:self.password error:nil]; break; case ConnectToServerPurposeRegister: [self.xmppStream registerWithPassword:self.registerPassword error:nil]; break; default: break; } } // 断开连接 - (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error { // 自己手动断开 // 被动断开 if (error) { NSLog(@"断开连接,erroe = @%@", error); } } // 认证失败 - (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error { NSLog(@"认证失败:error = %@", error); } // 认证成功 - (void)xmppStreamDidAuthenticate:(XMPPStream *)sender { // 上线 XMPPPresence *presence = [XMPPPresence presenceWithType:@"available"]; [self.xmppStream sendElement:presence]; NSLog(@"认证成功"); }
未完待续...
时间: 2024-10-11 07:32:46