赞
踩
在看这篇之前,如果您还不了解直播原理,请查看这篇文章如何快速的开发一个完整的iOS直播app(原理篇)
在直播中,聊天和发礼物,需要用到及时通讯技术,市面上的App大多数采用的都是第三方SDK,融云,环信等,但是本例子采用websocket搭建及时通讯服务器。
如果喜欢我的文章,可以关注我微博:袁峥Seemygo
即时通讯(Instant messaging,简称IM)是一个终端服务,允许两人或多人使用网路即时的传递文字讯息、档案、语音与视频交流
心跳包
:就是在客户端和服务器间定时通知对方自己状态的一个自己定义的命令字,按照一定的时间间隔发送,类似于心跳,所以叫做心跳包 什么是websocket?WebSocket 是一种双向通信协议,在建立连接后,WebSocket 服务器和 客户端 都能主动的向对方发送或接收数据。
服务器根据协议头判断是Http,还是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
Sec-WebSocket-Key:其值采用base64编码的随机16字节长的字符序列
为什么要使用Socket.IO?WebSocket的功能是很强大的,使用起来也灵活,可以适用于不同的场景。不过WebSocket技术也比较复杂,需要加密解密,包装协议,自己实现3次握手,还需要对数据流进行加密解密处理,服务器端和浏览器端的实现都不同于一般的Web应用,因此自己实现很麻烦,可以使用Socket.IO框架。
Socket.IO:是一个完全由JavaScript实现、基于Node.js、支持WebSocket的协议用于实时通信、跨平台的开源框架。
Socket.IO:它包括了客户端(iOS,Android)和服务器端(Node.js)的代码,可以很好的实现iOS即使通讯技术。
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连接(服务器不需要主动建立连接,建立连接是客户端的事情,服务器只需要监听连接)
发送和接受事件
触发服务器和客户端之间的通讯,任何能被编辑成JSON或二进制的对象都可以传递。- // 监听socket连接
- // function参数必填socket
- socket.on('connection',function(clientSocket){
- console.log('建立连接',clientSocket);
- });
-
2.下载完了,直接把Source文件夹拖入到自己工程中.
3.OC和Swift混编,Swift代码怎么在OC中使用,直接导入"工程文件名-Swift.h"就可以使用,这个文件Xcode会自动帮我们生成,无序手动自己生成.
#import "客户端-Swift.h"
4.注意工程文件名不能带有-这个符号,而且有时候会延迟,并不是马上导入"工程文件名-Swift.h"就好.
5.创建socket对象,然后连接用connect方法,socket对象需要强引用
注意协议:ws开头
创建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方法两个参数(第一个参数,监听的事件名称,第二个参数:监听事件回调函数,会自动调用)
ACK只是一个标记,标记是否成功传输数据。
- 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调用join,服务器就会把客户端socket和分组的名称绑定起来,到时候就可以根据分组的名称找到对应客户端的socket,就能给指定的客户端推送信息.- // 监听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的数据');
- });
-
- });
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。