关于websocket
我们都知道socket是套接字,描述ip地址和端口,它本身并不是协议,而是一个调用接口,为了大家直接使用更底层的协议(TCP或UDP),是对TCP/IP 或 UDP/IP的封装。socket处于网络层中的第五层,是一个抽象层。websocket是一个协议,是基于http协议的,是建立在TCP连接之上的,是应用层上的一个应用层协议,和socket不是一个概念。
websocket的特点
websocket可以传输文本和二进制。
websocket的协议头是ws开头的,并不是http。
框架
在iOS 平台上,我们知道socket的开源框架有 CocoaAsyncSocket, 而websocket的框架有Facebook的 SocketRocket, 以及socket.io-client-swift。
SocketRocket的使用
使用cocoapods集成
pod 'SocketRocket', '~> 0.5.1'
创建方法
self.wSocket = [[SRWebSocket alloc] initWithURL:[NSURL URLWithString:@“ws://192.168.2.21:8080”]];
self.wSocket.delegate = self;
[self.wSocket open];
这里要特别注意格式
ws://ip地址:端口号
如果服务器使用的框架是socket.io,客户端和服务器进行连接,客户端实现了SRWebSocketDelegate的代理方法后,并没有在打开成功的方法中实现回调,而是直接实现了关闭的(didCloseWithCode)回调,打印的结果如下:
code:1001, reason:Stream end encountered, wasClean:0
那么 这里的url就应该再进行一下参数拼接了
@“ws://192.168.2.21:8080” 改成
@“ws://192.168.2.21:8080/socket.io/?EIO=4&transport=websocket”
遵守SRWebSocketDelegate协议并实现代理方法
接收消息的代理方法是必须实现的,要不然就crash了
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;
下面的代理方法展示的是,当前websocket的连接状态,open,fail,close,receivePong
// 打开websocket成功的回调
- (void)webSocketDidOpen:(SRWebSocket *)webSocket;
// 发生错误的回调
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
// websocket关闭的回调
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean;
// 来着服务器pong消息
- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload;
关于 didReceivePong方法的理解
使用webSocket时,最好建立一个心跳包,用于每隔一段时间(5s也好十几秒也好)通知一次服务端,告诉服务器,客户端还活着,这就是一个ping消息。然后呢,服务器返回给客户端一个pong消息,这个pong消息呢,就在 didReceivePong 这个代理方法中去接收。
客户端发送消息的方法:
- (void)send:(id)data;
在发送信息的时候,要和服务器进行商量,格式是什么样的,如果格式不对的话,每发送一次,websocket都会关闭一次,这就很蛋疼了。
发送消息的时候,最好是创建一个模型 -> 转字典-> 转data-> 转成字符串。最后发送给服务器的就是这个字符串了。
XQMessage* message = [[XQMessage alloc] initWithMessage:textField.text userId: userTextField.text];
NSError* error;
NSData* data = [NSJSONSerialization dataWithJSONObject:message.mj_keyValues options:0 error:&error];
[self.wSocket send:[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]];
在接收到消息didReceiveMessage的方法中,再把服务器传过来的数据,转换成模型,方便使用。
学会了简单的使用socketRocket之后呢,最好封装一个工具类,来进行统一的管理,外界方便使用调用。需要注意的事,在封装的过程中,要定义一个属性state,表示websocket的连接状态,是关闭?连接中?已连接?连接错误?系统关闭?用户关闭?接收到信息等。根据实际的需求去做一些相应的处理。