貌似進入2016年就沒再更新簡書,把寫作忘了。罪過。
OK,進入正題,開始今天的技術講解。
太概念的知識網上有很多,我只做概括和快速并正確的使用。
Socket,即使用套接字連接,實際上是對TCP/UDP的再次封裝。
在一般項目中,使用Socket的情況很少,一般都會使用http實現客戶端與服務器端的通信。并且是單向的。
但http只能通過客戶端向服務器端主動發送網絡請求,服務器會對該次請求進行響應,回傳給客戶端一些數據。如果客戶端不主動向服務器端發送網絡請求,服務器端是不能主動向客戶端做出請求/響應操作的。
所以,為了實現服務器端可以主動向客戶端發送請求,我們使用Socket來實現這一需求。
上代碼:
1、先到github下載一個非常牛逼的庫,地址:https://github.com/robbiehanson/CocoaAsyncSocket
下載到本地后,有兩個文件夾:GCD / RunLoop
我個人比較喜歡使用GCD文件。看你擅長哪個技術就選擇哪個文件吧。原理都是相同的。
2、將你想使用的文件拖到項目中。
3、一般我們使用第三方庫都不會直接使用第三庫中某個類或方法,而是對第三方庫進行再次封裝。.h文件如圖:
GCDSocketManager是我封裝第三方的一個封裝類。
對外操作都靠這個類來完成。所以我使用了單例模式供全局使用。
4、.m文件
幾個需要注意的點:
(1)封裝類必須要實現第三方庫的GCDAsynSocketDelegate協議
(2)握手次數:客戶端和服務器端每次連接傳遞消息都會校驗,校驗就會根據握手次數。(socket的原理不多說了)
(3)斷開重連定時器:特別需要謹記的是只有當前項目在前臺運行時才可以保持長連接的狀態,當項目進入后臺就會斷開長連接,別問為什么。如果你想在程序進入后臺扔可以接到服務器主動給你發送的消息,使用推送服務。定時器在這里的作用就是,在當前程序處于前臺,如果socket連接失敗了要讓它自動重連。每隔一段時間讓socket自動連接一次。為了運行效率著想,這個時間可以每次進行累加。
(4)重連次數:我的重連次數就是用于時間的累加,第一次連接不上就1秒后重連,第二次連接不上就2秒后重連,以此累加。
5、.m文件的具體實現
繼續下一個
繼續下一個
繼續下一個
有連接成功,肯定也會有連接失敗,以下是對失敗事件的處理:
繼續下一個
連接成功處理完了,連接失敗也處理完了。
做事有始有終,有連接,自然也要有斷開。
好,以下是對代碼的調用時機和代碼的使用細節進行一些講解。
(1)什么時候進行長連?
長連當然是用戶登錄成功之后需要進行長連。
程序從后臺切換到前臺也需要進行長連。
所以可以把進行連接的代碼寫在根控制器中。
(2)什么時候斷開長連?
前面說過,程序進入后臺是要斷開的。所以在Application進入后臺時調用的那個生命周期方法里寫斷開長連的代碼。
(3)關于兩句很重要的代碼
timeout,超時時間。根據實際需求去設置,我這里設置為-1。
tag:發送數據和讀取數據的tag值一定不能設置成一樣的。
為什么不能設置成一樣的呢?舉個例子。
在這里tag相當于一個通道,并且在這個通道中只能完成一件事情。
如果這個通道專門用來發送數據的,就給這個通道打個標簽,標簽值就是1吧。
如果這個通道專門用來讀取數據的,就給這個通道打個標簽,標簽紙就是200把。
數值隨便定義,只能你能確保兩者的tag值不一樣。
但還有一個細節需要注意。
我在上圖代碼中再次調用了讀取數據的代碼,這里的tag值要始終保持一致。
那么在這里寫這句代碼有啥用呢?
在寫這句代碼前,我們已經在連接成功的代理方法中寫了這句代碼。
在上圖的代理方法中我可以讀取服務器響應的數據。
讀取完這一次服務器響應的數據后,下一次服務器再次發送數據我們該怎么讀取?
就是通過這句代碼,所以在這里再寫一次。
這樣我們就可以保證每次服務器響應的數據,我們客戶端都可以正常讀取了。
6、心跳包
心跳包。。就是一個數據包。
每隔一段時間向服務器傳輸一次你的數據。
當然是使用定時器實現了。代碼就不上了哈。
到這里,又出現了一個新問題。
剛才已經說了,程序在前臺才能保持長連。
程序進入后臺長連就斷了。
那么,當程序在后臺時依然需要每隔一段時間向服務器發送一次心跳包,這個需求,怎么實現?
請聽下回講解。