關(guān)于websocket
我們都知道socket是套接字,描述ip地址和端口混聊,它本身并不是協(xié)議弹谁,而是一個(gè)調(diào)用接口,為了大家直接使用更底層的協(xié)議(TCP或UDP)句喜,是對TCP/IP 或 UDP/IP的封裝预愤。socket處于網(wǎng)絡(luò)層中的第五層,是一個(gè)抽象層咳胃。websocket是一個(gè)協(xié)議植康,是基于http協(xié)議的,是建立在TCP連接之上的展懈,是應(yīng)用層上的一個(gè)應(yīng)用層協(xié)議销睁,和socket不是一個(gè)概念供璧。
websocket的特點(diǎn)
websocket可以傳輸文本和二進(jìn)制。
websocket的協(xié)議頭是ws開頭的冻记,并不是http睡毒。
框架
在iOS 平臺上,我們知道socket的開源框架有 CocoaAsyncSocket冗栗, 而websocket的框架有Facebook的 SocketRocket演顾, 以及socket.io-client-swift。
SocketRocket的使用
使用cocoapods集成
pod 'SocketRocket', '~> 0.5.1'
創(chuàng)建方法
self.wSocket = [[SRWebSocket alloc] initWithURL:[NSURL URLWithString:@“ws://192.168.2.21:8080”]];
self.wSocket.delegate = self;
[self.wSocket open];
這里要特別注意格式
ws://ip地址:端口號
如果服務(wù)器使用的框架是socket.io贞瞒,客戶端和服務(wù)器進(jìn)行連接偶房,客戶端實(shí)現(xiàn)了SRWebSocketDelegate的代理方法后,并沒有在打開成功的方法中實(shí)現(xiàn)回調(diào)军浆,而是直接實(shí)現(xiàn)了關(guān)閉的(didCloseWithCode)回調(diào),打印的結(jié)果如下:
code:1001, reason:Stream end encountered, wasClean:0
那么 這里的url就應(yīng)該再進(jìn)行一下參數(shù)拼接了
@“ws://192.168.2.21:8080” 改成
@“ws://192.168.2.21:8080/socket.io/?EIO=4&transport=websocket”
遵守SRWebSocketDelegate協(xié)議并實(shí)現(xiàn)代理方法
接收消息的代理方法是必須實(shí)現(xiàn)的挡闰,要不然就crash了
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;
下面的代理方法展示的是乒融,當(dāng)前websocket的連接狀態(tài),open摄悯,fail赞季,close,receivePong
// 打開websocket成功的回調(diào)
- (void)webSocketDidOpen:(SRWebSocket *)webSocket;
// 發(fā)生錯(cuò)誤的回調(diào)
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
// websocket關(guān)閉的回調(diào)
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean;
// 來著服務(wù)器pong消息
- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload;
關(guān)于 didReceivePong方法的理解
使用webSocket時(shí)奢驯,最好建立一個(gè)心跳包申钩,用于每隔一段時(shí)間(5s也好十幾秒也好)通知一次服務(wù)端,告訴服務(wù)器瘪阁,客戶端還活著撒遣,這就是一個(gè)ping消息。然后呢管跺,服務(wù)器返回給客戶端一個(gè)pong消息义黎,這個(gè)pong消息呢,就在 didReceivePong 這個(gè)代理方法中去接收豁跑。
客戶端發(fā)送消息的方法:
- (void)send:(id)data;
在發(fā)送信息的時(shí)候廉涕,要和服務(wù)器進(jìn)行商量,格式是什么樣的艇拍,如果格式不對的話狐蜕,每發(fā)送一次,websocket都會關(guān)閉一次卸夕,這就很蛋疼了层释。
發(fā)送消息的時(shí)候,最好是創(chuàng)建一個(gè)模型 -> 轉(zhuǎn)字典-> 轉(zhuǎn)data-> 轉(zhuǎn)成字符串娇哆。最后發(fā)送給服務(wù)器的就是這個(gè)字符串了湃累。
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的方法中勃救,再把服務(wù)器傳過來的數(shù)據(jù),轉(zhuǎn)換成模型治力,方便使用蒙秒。
學(xué)會了簡單的使用socketRocket之后呢,最好封裝一個(gè)工具類宵统,來進(jìn)行統(tǒng)一的管理晕讲,外界方便使用調(diào)用。需要注意的事马澈,在封裝的過程中瓢省,要定義一個(gè)屬性state,表示websocket的連接狀態(tài)痊班,是關(guān)閉勤婚?連接中?已連接涤伐?連接錯(cuò)誤疟暖?系統(tǒng)關(guān)閉扬舒?用戶關(guān)閉?接收到信息等。根據(jù)實(shí)際的需求去做一些相應(yīng)的處理劣光。