微信,QQ这类IM app怎么做——谈谈Websocket
本文轉(zhuǎn)載至?https://mp.weixin.qq.com/s?__biz=MjM5OTM0MzIwMQ==&mid=2652545551&idx=1&sn=403b75d95cf191ef640463b5e14419ce&scene=1&srcid=05308WuAcPhRpSfRtpD45yOM&key=f5c31ae61525f82e6097caed39d586b9f52a465ea5b44023a82ba607a7f851c58a2d91e62a3c778e2ac522ed1cd8be19&ascene=0&uin=MTc0NjU0MjE2Mw%3D%3D&devicetype=iMac+MacBookPro11%2C1+OSX+OSX+10.11.4+build(15E65)&version=11020201&pass_ticket=r%2FSz%2BHLukX%2BWabrgKVjzu%2FQxXZP1FAkZQPCVsm7MWiduGdgcrSdszaENxzmDC92y
?
前言
?
關(guān)于我和WebSocket的緣:我從大二在計算機(jī)網(wǎng)絡(luò)課上聽老師講過之后,第一次使用就到了畢業(yè)之后的第一份工作。直到最近換了工作,到了一家是含有IM社交聊天功能的app的時候,我覺得我現(xiàn)在可以談?wù)勎覍ebSocket/Socket的一些看法了。要想做IM聊天app,就不得不理解WebSocket和Socket的原理了,聽我一一道來。
?
目錄
?
1.WebSocket使用場景
2.WebSocket誕生由來
3.談?wù)刉ebSocket協(xié)議原理
4.WebSocket 和 Socket的區(qū)別與聯(lián)系
5.iOS平臺有哪些WebSocket和Socket的開源框架
6.iOS平臺如何實現(xiàn)WebSocket協(xié)議
?
一.WebSocket的使用場景
?
1.社交聊天
?
最著名的就是微信,QQ,這一類社交聊天的app。這一類聊天app的特點是低延遲,高即時。即時是這里面要求最高的,如果有一個緊急的事情,通過IM軟件通知你,假設(shè)網(wǎng)絡(luò)環(huán)境良好的情況下,這條message還無法立即送達(dá)到你的客戶端上,緊急的事情都結(jié)束了,你才收到消息,那么這個軟件肯定是失敗的。
?
2.彈幕
?
說到這里,大家一定里面想到了A站和B站了。確實,他們的彈幕一直是一種特色。而且彈幕對于一個視頻來說,很可能彈幕才是精華。發(fā)彈幕需要實時顯示,也需要和聊天一樣,需要即時。
?
3.多玩家游戲
?
4.協(xié)同編輯
?
現(xiàn)在很多開源項目都是分散在世界各地的開發(fā)者一起協(xié)同開發(fā),此時就會用到版本控制系統(tǒng),比如Git,SVN去合并沖突。但是如果有一份文檔,支持多人實時在線協(xié)同編輯,那么此時就會用到比如WebSocket了,它可以保證各個編輯者都在編輯同一個文檔,此時不需要用到Git,SVN這些版本控制,因為在協(xié)同編輯界面就會實時看到對方編輯了什么,誰在修改哪些段落和文字。
?
5.股票基金實時報價
?
金融界瞬息萬變——幾乎是每毫秒都在變化。如果采用的網(wǎng)絡(luò)架構(gòu)無法滿足實時性,那么就會給客戶帶來巨大的損失。幾毫秒錢股票開始大跌,幾秒以后才刷新數(shù)據(jù),一秒鐘的時間內(nèi),很可能用戶就已經(jīng)損失巨大財產(chǎn)了。
?
6.體育實況更新
?
全世界的球迷,體育愛好者特別多,當(dāng)然大家在關(guān)心自己喜歡的體育活動的時候,比賽實時的賽況是他們最最關(guān)心的事情。這類新聞中最好的體驗就是利用Websocket達(dá)到實時的更新!
?
7.視頻會議/聊天
?
視頻會議并不能代替和真人相見,但是他能讓分布在全球天涯海角的人聚在電腦前一起開會。既能節(jié)省大家聚在一起路上花費的時間,討論聚會地點的糾結(jié),還能隨時隨地,只要有網(wǎng)絡(luò)就可以開會。
?
8.基于位置的應(yīng)用
?
越來越多的開發(fā)者借用移動設(shè)備的GPS功能來實現(xiàn)他們基于位置的網(wǎng)絡(luò)應(yīng)用。如果你一直記錄用戶的位置(比如運行應(yīng)用來記錄運動軌跡),你可以收集到更加細(xì)致化的數(shù)據(jù)。
?
9.在線教育
?
在線教育近幾年也發(fā)展迅速。優(yōu)點很多,免去了場地的限制,能讓名師的資源合理的分配給全國各地想要學(xué)習(xí)知識的同學(xué)手上,Websocket是個不錯的選擇,可以視頻聊天、即時聊天以及其與別人合作一起在網(wǎng)上討論問題...
?
10.智能家居
?
這也是我一畢業(yè)加入的一個偉大的物聯(lián)網(wǎng)智能家居的公司。考慮到家里的智能設(shè)備的狀態(tài)必須需要實時的展現(xiàn)在手機(jī)app客戶端上,毫無疑問選擇了Websocket。
?
11.總結(jié)
?
從上面我列舉的這些場景來看,一個共同點就是,高實時性!
?
二.WebSocket誕生由來
?
1.最開始的輪詢Polling階段
這種方式下,是不適合獲取實時信息的,客戶端和服務(wù)器之間會一直進(jìn)行連接,每隔一段時間就詢問一次。客戶端會輪詢,有沒有新消息。這種方式連接數(shù)會很多,一個接受,一個發(fā)送。而且每次發(fā)送請求都會有Http的Header,會很耗流量,也會消耗CPU的利用率。
?
2.改進(jìn)版的長輪詢Long polling階段
長輪詢是對輪詢的改進(jìn)版,客戶端發(fā)送HTTP給服務(wù)器之后,有沒有新消息,如果沒有新消息,就一直等待。當(dāng)有新消息的時候,才會返回給客戶端。在某種程度上減小了網(wǎng)絡(luò)帶寬和CPU利用率等問題。但是這種方式還是有一種弊端:例如假設(shè)服務(wù)器端的數(shù)據(jù)更新速度很快,服務(wù)器在傳送一個數(shù)據(jù)包給客戶端后必須等待客戶端的下一個Get請求到來,才能傳遞第二個更新的數(shù)據(jù)包給客戶端,那么這樣的話,客戶端顯示實時數(shù)據(jù)最快的時間為2×RTT(往返時間),而且如果在網(wǎng)絡(luò)擁塞的情況下,這個時間用戶是不能接受的,比如在股市的的報價上。另外,由于http數(shù)據(jù)包的頭部數(shù)據(jù)量往往很大(通常有400多個字節(jié)),但是真正被服務(wù)器需要的數(shù)據(jù)卻很少(有時只有10個字節(jié)左右),這樣的數(shù)據(jù)包在網(wǎng)絡(luò)上周期性的傳輸,難免對網(wǎng)絡(luò)帶寬是一種浪費。
?
3.WebSocket誕生
?
現(xiàn)在急需的需求是能支持客戶端和服務(wù)器端的雙向通信,而且協(xié)議的頭部又沒有HTTP的Header那么大,于是,Websocket就誕生了!
上圖就是Websocket和Polling的區(qū)別,從圖中可以看到Polling里面客戶端發(fā)送了好多Request,而下圖,只有一個Upgrade,非常簡潔高效。至于消耗方面的比較就要看下圖了
上圖中,我們先看藍(lán)色的柱狀圖,是Polling輪詢消耗的流量,
Use case A:?1,000 clients polling every second: Network throughput is (871 x 1,000) = 871,000 bytes = 6,968,000 bits per second (6.6 Mbps)
?
Use case B:?10,000 clients polling every second: Network throughput is (871 x 10,000) = 8,710,000 bytes = 69,680,000 bits per second (66 Mbps)
?
Use case C:?100,000 clients polling every 1 second: Network throughput is (871 x 100,000) = 87,100,000 bytes = 696,800,000 bits per second (665 Mbps)
而Websocket的Frame是 just two bytes of overhead instead of 871,僅僅用2個字節(jié)就代替了輪詢的871字節(jié)!
?
Use case A:?1,000 clients receive 1 message per second: Network throughput is (2 x 1,000) = 2,000 bytes = 16,000 bits per second (0.015 Mbps)
?
Use case B:?10,000 clients receive 1 message per second: Network throughput is (2 x 10,000) = 20,000 bytes = 160,000 bits per second (0.153 Mbps)
?
Use case C:?100,000 clients receive 1 message per second: Network throughput is (2 x 100,000) = 200,000 bytes = 1,600,000 bits per second (1.526 Mbps)
?
相同的每秒客戶端輪詢的次數(shù),當(dāng)次數(shù)高達(dá)10W/s的高頻率次數(shù)的時候,Polling輪詢需要消耗665Mbps,而Websocket僅僅只花費了1.526Mbps,將近435倍!!
?
三.談?wù)刉ebSocket協(xié)議原理
?
Websocket是應(yīng)用層第七層上的一個應(yīng)用層協(xié)議,它必須依賴?HTTP 協(xié)議進(jìn)行一次握手?,握手成功后,數(shù)據(jù)就直接從 TCP 通道傳輸,與 HTTP 無關(guān)了。
?
Websocket的數(shù)據(jù)傳輸是frame形式傳輸?shù)?#xff0c;比如會將一條消息分為幾個frame,按照先后順序傳輸出去。這樣做會有幾個好處:
?
1)大數(shù)據(jù)的傳輸可以分片傳輸,不用考慮到數(shù)據(jù)大小導(dǎo)致的長度標(biāo)志位不足夠的情況。
2)和http的chunk一樣,可以邊生成數(shù)據(jù)邊傳遞消息,即提高傳輸效率。
四.WebSocket 和 Socket的區(qū)別與聯(lián)系
?
首先,Socket 其實并不是一個協(xié)議。它工作在 OSI 模型會話層(第5層),是為了方便大家直接使用更底層協(xié)議(一般是 TCP 或 UDP )而存在的一個抽象層。Socket是對TCP/IP協(xié)議的封裝,Socket本身并不是協(xié)議,而是一個調(diào)用接口(API)。
Socket通常也稱作”套接字”,用于描述IP地址和端口,是一個通信鏈的句柄。網(wǎng)絡(luò)上的兩個程序通過一個雙向的通訊連接實現(xiàn)數(shù)據(jù)的交換,這個雙向鏈路的一端稱為一個Socket,一個Socket由一個IP地址和一個端口號唯一確定。應(yīng)用程序通常通過”套接字”向網(wǎng)絡(luò)發(fā)出請求或者應(yīng)答網(wǎng)絡(luò)請求。
?
Socket在通訊過程中,服務(wù)端監(jiān)聽某個端口是否有連接請求,客戶端向服務(wù)端發(fā)送連接請求,服務(wù)端收到連接請求向客戶端發(fā)出接收消息,這樣一個連接就建立起來了。客戶端和服務(wù)端也都可以相互發(fā)送消息與對方進(jìn)行通訊,直到雙方連接斷開。
?
所以基于WebSocket和基于Socket都可以開發(fā)出IM社交聊天類的app
?
五.iOS平臺有哪些WebSocket和Socket的開源框架
?
Socket開源框架有:CocoaAsyncSocket,socketio/socket.io-client-swift
WebSocket開源框架有:facebook/SocketRocket,tidwall/SwiftWebSocket
?
六.iOS平臺如何實現(xiàn)WebSocket協(xié)議
?
Talk is cheap。Show me the code ——Linus Torvalds
?
我們今天來看看facebook/SocketRocket的實現(xiàn)方法
?
首先這是SRWebSocket定義的一些成員變量
?
@property?(nonatomic,?weak)?id??delegate; /** ?A?dispatch?queue?for?scheduling?the?delegate?calls.?The?queue?doesn't?need?be?a?serial?queue. ?If?`nil`?and?`delegateOperationQueue`?is?`nil`,?the?socket?uses?main?queue?for?performing?all?delegate?method?calls. ?*/ @property?(nonatomic,?strong)?dispatch_queue_t?delegateDispatchQueue; /** ?An?operation?queue?for?scheduling?the?delegate?calls. ?If?`nil`?and?`delegateOperationQueue`?is?`nil`,?the?socket?uses?main?queue?for?performing?all?delegate?method?calls. ?*/ @property?(nonatomic,?strong)?NSOperationQueue?*delegateOperationQueue; @property?(nonatomic,?readonly)?SRReadyState?readyState; @property?(nonatomic,?readonly,?retain)?NSURL?*url; @property?(nonatomic,?readonly)?CFHTTPMessageRef?receivedHTTPHeaders; //?Optional?array?of?cookies?(NSHTTPCookie?objects)?to?apply?to?the?connections @property?(nonatomic,?copy)?NSArray?*requestCookies; //?This?returns?the?negotiated?protocol. //?It?will?be?nil?until?after?the?handshake?completes. @property?(nonatomic,?readonly,?copy)?NSString?*protocol;?
下面這些是SRWebSocket的一些方法
?
//?Protocols?should?be?an?array?of?strings?that?turn?into?Sec-WebSocket-Protocol. -?(instancetype)initWithURLRequest:(NSURLRequest?*)request; -?(instancetype)initWithURLRequest:(NSURLRequest?*)request?protocols:(NSArray?*)protocols; -?(instancetype)initWithURLRequest:(NSURLRequest?*)request?protocols:(NSArray?*)protocols?allowsUntrustedSSLCertificates:(BOOL)allowsUntrustedSSLCertificates; //?Some?helper?constructors. -?(instancetype)initWithURL:(NSURL?*)url; -?(instancetype)initWithURL:(NSURL?*)url?protocols:(NSArray?*)protocols; -?(instancetype)initWithURL:(NSURL?*)url?protocols:(NSArray?*)protocols?allowsUntrustedSSLCertificates:(BOOL)allowsUntrustedSSLCertificates; //?By?default,?it?will?schedule?itself?on?+[NSRunLoop?SR_networkRunLoop]?using?defaultModes. -?(void)scheduleInRunLoop:(NSRunLoop?*)aRunLoop?forMode:(NSString?*)mode; -?(void)unscheduleFromRunLoop:(NSRunLoop?*)aRunLoop?forMode:(NSString?*)mode; //?SRWebSockets?are?intended?for?one-time-use?only.??Open?should?be?called?once?and?only?once. -?(void)open; -?(void)close; -?(void)closeWithCode:(NSInteger)code?reason:(NSString?*)reason; ///-------------------------------------- #pragma?mark?Send ///-------------------------------------- //下面是4個發(fā)送的方法 /** ?Send?a?UTF-8?string?or?binary?data?to?the?server. ?@param?message?UTF-8?String?or?Data?to?send. ?@deprecated?Please?use?`sendString:`?or?`sendData`?instead. ?*/ -?(void)send:(id)message?__attribute__((deprecated("Please?use?`sendString:`?or?`sendData`?instead."))); -?(void)sendString:(NSString?*)string; -?(void)sendData:(NSData?*)data; -?(void)sendPing:(NSData?*)data; @end?
對應(yīng)5種狀態(tài)的代理方法
?
///-------------------------------------- #pragma?mark?-?SRWebSocketDelegate ///-------------------------------------- @protocol?SRWebSocketDelegate?-?(void)webSocket:(SRWebSocket?*)webSocket?didReceiveMessage:(id)message; @optional -?(void)webSocketDidOpen:(SRWebSocket?*)webSocket; -?(void)webSocket:(SRWebSocket?*)webSocket?didFailWithError:(NSError?*)error; -?(void)webSocket:(SRWebSocket?*)webSocket?didCloseWithCode:(NSInteger)code?reason:(NSString?*)reason?wasClean:(BOOL)wasClean; -?(void)webSocket:(SRWebSocket?*)webSocket?didReceivePong:(NSData?*)pongPayload; //?Return?YES?to?convert?messages?sent?as?Text?to?an?NSString.?Return?NO?to?skip?NSData?->?NSString?conversion?for?Text?messages.?Defaults?to?YES. -?(BOOL)webSocketShouldConvertTextFrameToString:(SRWebSocket?*)webSocket; @end?
didReceiveMessage方法是必須實現(xiàn)的,用來接收消息的。
?
下面4個did方法分別對應(yīng)著Open,Fail,Close,ReceivePong不同狀態(tài)的代理方法
?
方法就上面這些了,我們實際來看看代碼怎么寫
?
先是初始化Websocket連接,注意此處ws://或者wss://連接有且最多只能有一個,這個是Websocket協(xié)議規(guī)定的
?
self.ws?=?[[SRWebSocket?alloc]?initWithURLRequest:[NSURLRequest?requestWithURL:[NSURL?URLWithString:[NSString? stringWithFormat:@"%@://%@:%zd/ws",?serverProto,?serverIP,?serverPort]]]]; ????self.ws.delegate?=?delegate; ????[self.ws?open];?
發(fā)送消息
?
[self.ws?send:message];
?
接收消息以及其他3個代理方法
?
| //這個就是接受消息的代理方法了,這里接受服務(wù)器返回的數(shù)據(jù),方法里面就應(yīng)該寫處理數(shù)據(jù),存儲數(shù)據(jù)的方法了。 -?(void)webSocket:(SRWebSocket?*)webSocket?didReceiveMessage:(id)message { ????NSDictionary?*data?=?[NetworkUtils?decodeData:message]; ????if?(!data) ????????return; } //這里是Websocket剛剛Open之后的代理方法。就想微信剛剛連接中,會顯示連接中,當(dāng)連接上了,就不顯示連接中了,取消顯示連接的方法就應(yīng)該寫在這里面 -?(void)webSocketDidOpen:(SRWebSocket?*)webSocket { ????//?Open?=?silent?ping ????[self.ws?receivedPing]; } //這是關(guān)閉Websocket的代理方法 -?(void)webSocket:(SRWebSocket?*)webSocket?didCloseWithCode:(NSInteger)code?reason:(NSString?*)reason?wasClean:(BOOL)wasClean { ????[self?failedConnection:NSLS(Disconnected)]; } //這里是連接Websocket失敗的方法,這里面一般都會寫重連的方法 -?(void)webSocket:(SRWebSocket?*)webSocket?didFailWithError:(NSError?*)error { ????[self?failedConnection:NSLS(Disconnected)]; } |
?
最后
?
以上就是我想分享的一些關(guān)于Websocket的心得,文中如果有錯誤的地方,歡迎大家指點!一般沒有微信QQ那么大用戶量的app,用Websocket應(yīng)該都可以完成IM社交聊天的任務(wù)。當(dāng)用戶達(dá)到億級別,應(yīng)該還有很多需要優(yōu)化,優(yōu)化性能各種的吧。
?
最后,微信和QQ的實現(xiàn)方法也許并不是只用Websocket和Socket這么簡單,也許是他們自己開發(fā)的一套能支持這么大用戶,大數(shù)據(jù)的,各方面也都優(yōu)化都最優(yōu)的方法。如果有開發(fā)和微信和QQ的大神看到這篇文章,可以留言說說看你們用什么方式實現(xiàn)的,也可以和我們一起分享,我們一起學(xué)習(xí)!我先謝謝大神們的指點了!
轉(zhuǎn)載于:https://www.cnblogs.com/Camier-myNiuer/p/5542107.html
總結(jié)
以上是生活随笔為你收集整理的微信,QQ这类IM app怎么做——谈谈Websocket的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: bootstrap源码分析之form、n
- 下一篇: 任意进制转换算法