在看这篇之前,如果您还不了解直播原理,请查看这篇文章如何快速的开发一个完整的iOS直播app(原理篇)
在直播中,聊天和发礼物,需要用到及时通讯技术,市面上的App大多数采用的都是第三方SDK,融云,环信等,但是本例子采用websocket搭建及时通讯服务器。
如果喜欢我的文章,可以关注我微博:袁峥Seemygo,也可以来小码哥,了解下我们的iOS培训课程。后续还会更新更多内容,有任何问题,欢迎简书留言袁峥Seemygo。。。
即时通讯(Instant messaging,简称IM)是一个终端服务,允许两人或多人使用网路即时的传递文字讯息、档案、语音与视频交流
Websocket协议解析:
请求头
GET ws://localhost:12345/websocket/test.html HTTP/1.1
Origin: http://localhost
Connection: Upgrade
Host: localhost:12345
Sec-WebSocket-Key: JspZdPxs9MrWCt3j6h7KdQ== //主要这个字段,这个叫“梦幻字符串”,这个也是个密钥,只有有这个密钥 服务器才能通过解码 认出来,哦~这是个WB的请求,我要建立TCP连接了!!!如果这个字符串没有按照加密规则加密,那服务端就认不出来,就会认为这整个协议就是个HTTP请求。更不会开TCP。其他的字段都可以随便设置,但是这个字段是最重要的字段,标识WB协议的一个字段。
Upgrade: websocket
Sec-WebSocket-Version: 13
响应头
HTTP/1.1 101 Web Socket Protocol Handshake
WebSocket-Location: ws://localhost:12345/websocket/test.php
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: zUyzbJdkVJjhhu8KiAUCDmHtY/o= //这个字段,叫“梦幻字符串”,和上面那个梦幻字符串作用一样。不同的是,这个字符串是要让客户端辨认的,客户端拿到后自动解码。并且辨认是不是一个WB请求。然后进行相应的操作。这个字段也是重中之重,不可随便修改的。加密规则,依然是有规则的,可以去百度一下。
WebSocket-Origin: http://localhost
WebSocket的功能是很强大的,使用起来也灵活,可以适用于不同的场景。不过WebSocket技术也比较复杂,需要加密解密,包装协议,自己实现3次握手,还需要对数据流进行加密解密处理,服务器端和浏览器端的实现都不同于一般的Web应用,因此自己实现很麻烦,可以使用Socket.IO框架。
Socket.IO:是一个完全由JavaScript实现、基于Node.js、支持WebSocket的协议用于实时通信、跨平台的开源框架。
Socket.IO:它包括了客户端(iOS,Android)和服务器端(Node.js)的代码,可以很好的实现iOS即使通讯技术。
Socket.IO框架地址
1.如何导入Socket.IO?
"dependencies": {
"express": "^4.14.0",
"socket.io": "^1.4.8"
}
2.如何创建socket
socket本质还是http协议,所以需要绑定http服务器,才能启动socket服务.
而且需要通过web服务器监听端口,socket不能监听端口,有人访问端口才能建立连接,所以先创建web服务器
* 1.面向express框架开发,加载express框架,方便处理get,post请求
* 2.因为socket依赖http,创建http服务器,使用http模块.
* 3.可以通过express创建http服务器http.server(express)
* 4.通过http服务器创建socket
* 5.监听http服务器
```
// 引入express
var http = require('http');
var express = require('express');
// 创建web服务器
var server = http.Server(express);
// 引入socker
var socketIO = require('socket.io');
// 需要传入服务器,socket基于http
var socket = socketIO(server);
// 监听web服务器
server.listen(8080);
```
3.如何建立socket连接(服务器不需要主动建立连接,建立连接是客户端的事情,服务器只需要监听连接)
// 监听socket连接
// function参数必填socket
socket.on('connection',function(clientSocket){
console.log('建立连接',clientSocket);
});
1.下载Socket.IO-Client-Swift
2.下载完了,直接把Source文件夹拖入到自己工程中.
3.OC和Swift混编,Swift代码怎么在OC中使用,直接导入"工程文件名-Swift.h"就可以使用,这个文件Xcode会自动帮我们生成,无序手动自己生成.
#import "客户端-Swift.h"
4.注意工程文件名不能带有-这个符号,而且有时候会延迟,并不是马上导入"工程文件名-Swift.h"就好.
5.创建socket对象,然后连接用connect方法,socket对象需要强引用
创建socket对象,需要传入字典,字典配置如下。
所有关于SocketIOClientOption的设置.如果是ObjC,转换名字lowerCamelCase.
case ConnectParams([String: AnyObject]) // 通过字典内容连接
case Cookies([NSHTTPCookie]) // An array of NSHTTPCookies. Passed during the handshake. Default is nil.
case DoubleEncodeUTF8(Bool) // Whether or not to double encode utf8. If using the node based server this should be true. Default is true.
case ExtraHeaders([String: String]) // 添加自定义请求头初始化来请求, 默认为nil
case ForcePolling(Bool) // 是否使用 xhr-polling. Default is `false`
case ForceNew(Bool) // 将为每个连接创建一个新的connect, 如果你在重新连接时有bug时使用.
case ForceWebsockets(Bool) // 是否使用 WebSockets. Default is `false`
case HandleQueue(dispatch_queue_t) // 调度handle的运行队列. Default is the main queue.
case Log(Bool) // 是否打印调试信息. Default is false.
case Logger(SocketLogger) // 可自定义SocketLogger调试日志.默认是系统的.
case Nsp(String) // 如果使用命名空间连接. Must begin with /. Default is `/`
case Path(String) // 如果服务器使用一个自定义路径. 例如: `"/swift/"`. Default is `""`
case Reconnects(Bool) // 是否重新连接服务器失败. Default is `true`
case ReconnectAttempts(Int) // 重新连接多少次. Default is `-1` (无限次)
case ReconnectWait(Int) // 等待重连时间. Default is `10`
case SessionDelegate(NSURLSessionDelegate) // NSURLSessionDelegate 底层引擎设置. 如果你需要处理自签名证书. Default is nil.
case Secure(Bool) // 如果连接要使用TLS. Default is false.
case SelfSigned(Bool) // WebSocket.selfSignedSSL设置 (Don't do this, iOS will yell at you)
case VoipEnabled(Bool) // 如果你的客户端使用VoIP服务,只有用这个选项,Default is false
6.因为需要进行3次握手,不可能马上建议连接,需要监听是否连接成功的回调,使用on方法
7.ON方法两个参数(第一个参数,监听的事件名称,第二个参数:监听事件回调函数,会自动调用)
NSURL *url = [NSURL URLWithString:@"ws://192.168.0.100:8080"];
SocketIOClient *socket = [[SocketIOClient alloc] initWithSocketURL:url config:@{@"log": @YES, @"forcePolling": @YES}];
_socket = socket;
[socket connect];
// 监听连接成功
[socket on:@"connect" callback:^(NSArray * _Nonnull data, SocketAckEmitter * _Nonnull ask) {
NSLog(@"确定与服务器连接");
NSLog(@"%@ %@",data,ask);
}];
[socket emit:@"chat" with:@[@"你好"]];
// 监听socket连接
socket.on('connection',function(s){
console.log('监听到客户端连接');
// data:客户端数组第0个元素
// data1:客户端数组第1个元素
s.on('chat',function(data,data1){
console.log('监听到chat事件');
console.log(data,data1);
});
});
socket.emit('chat','服务器'+data);
socket.emit.broadcast.emit('chat','发给所有客户端,不包含当前客户端'+data);
socket.emit.sockets.emit('chat','发给所有客户端,包含当前客户端'+data);
[socket on:@"chat" callback:^(NSArray * _Nonnull data, SocketAckEmitter * _Nonnull ask) {
NSLog(@"%@",data[0]);
}];
// 监听socket连接
socket.on('connection',function(s){
console.log('监听到客户端连接');
s.on('createRoom',function(roomName){
s.join(roomName);
rooms.push(roomName);
console.log('创建房间'+ roomName);
});
s.on('chatRoom',function(data){
console.log(rooms[0] + '说话');
socket.to(rooms[0]).emit('chat','房间1的数据');
});
});
原文地址:http://www.jianshu.com/p/6e7fb61c25e1