关于WebSocket实践记录

前言

由于公司有直播方面的业务,直播肯定需要弹幕功能,google了一番发现Websocket可以实现实时弹幕功能,然后在GitHub上发现了Facebook家的第三方框架SocketRocket,实现了弹幕功能.

WebSocket

WebSocket一种在单个 TCP 连接上进行全双工通讯的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并被RFC7936所补充规范。WebSocket API也被W3C定为标准。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

WebSocket 维基百科

SocketRocket

SocketRocket 是一个符合WebSocket协议的用于iOS, macOS, tvOS的第三方开发框架,能够增加我们开发效率.

特性

  • 同时支持IPv4/IPv6
  • 支持SSL证书
  • 似乎性能还不错
  • 支持TLS (wss)
  • 支持HTTP代理
  • 异步工作,大部分操作都在一个后台线程完成的并且不会阻塞

集成

CocoaPods集成

1
pod 'SocketRocket'

SocketRocket API

SocketRocket类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@interface SRWebSocket : NSObject

// 初始化方法
- (instancetype)initWithURLRequest:(NSURLRequest *)request;

// 代理需要在连接之前设置
@property (nonatomic, weak) id <SRWebSocketDelegate> delegate;

// 开始连接
- (void)open;

// 关闭连接
- (void)close;
- (void)closeWithCode:(NSInteger)code reason:(NSString *)reason;


// 发送数据
- (void)send:(id)data;

@end

SRWebSocketDelegate

项目中需要实现的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@protocol SRWebSocketDelegate <NSObject>

@optional

// 连接成功回调
- (void)webSocketDidOpen:(SRWebSocket *)webSocket;

// 接收到消息
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessageWithString:(NSString *)string;
// 接收到二进制数据
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessageWithData:(NSData *)data;

// 连接失败错误信息回调
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;

// 关闭连接以及错误码回调
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(nullable NSString *)reason wasClean:(BOOL)wasClean;

@end

项目中的实践

在连接成功之后发送用户信息(json字符串)给服务器(相当于登录)

1
2
3
4
5
6
7
8
9
10
11
12
- (void)webSocketDidOpen:(SRWebSocket *)webSocket
{
NSLog(@"连接成功webSocketDidOpen:%@",webSocket);
[self outputString:[NSString stringWithFormat:@"连接成功webSocketDidOpen:%@",webSocket] type:1];
[self outputString:[NSString stringWithFormat:@"连接地址:%@",webSocket.url.absoluteString] type:1];
self.closeButton.enabled = YES;

// 连接上之后,发送登录信息
// {"type":"login","uid":"1","topic_id":"bhy7zsa1f9"}
[self.socket send:@"{\"type\":\"login\",\"uid\":\"1\",\"topic_id\":\"bhy7zsa1f9\"}"];

}

接收服务器发送的数据type为ping的数据客户端需要回复pong,来维持长连接,这个是和后台商量定下来的.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message
{
[self outputString:message type:1];
NSLog(@"%@",message);

NSError *jsonError;
NSData *jsonData = [message dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *msgDict = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&jsonError];
NSString *type = msgDict[@"type"];
if ([type isEqualToString:@"ping"]) {
[self.socket send:@"{\"type\":\"pong\"}"];
[self outputString:@"{\"type\":\"pong\"}" type:2] ;
}
}

发送数据给服务器,根据实际情况调用对应的方法即可,公司项目我和后台约定的是传json字符串所以调用的sendString:error:方法

1
2
// 发送数据
- (void)send:(id)data;

其他

WebSocketDemo

SRWebSocket

阅读原文