websocket是一種全雙工協議,何謂全雙工,即客戶端和伺服器通信時在同一時刻即可以發送數據又可以接收數據。與之相反的http是半雙工,在http通信的過程中,一次只能執行一種操作,發送和接受不能同時進行。半雙工功能弱,但簡單;全雙工功能強,但是複雜。 在項目中我們應該使用websocket還是http,這個需要視需求而定,不經過深思熟慮的隨意選擇容易產生副作用,雖然這兩種協議通常都能實現我們的需求。

最近開發一款微信H5遊戲,完全使用websocket協議,在項目上線後出現了許多問題都是由於過度使用websocket而引起,接下來我就談談因為開發這個項目而領悟到的相關使用websocket的經驗。

使用websocket有一個前提,在發送數據之前必須要創建連接,只有連接存在纔可以傳遞數據。有人或許會反問,通過http傳遞數據不也需要建立連接嗎。 話雖如此,websocket和http都是基於tcp,客戶端與伺服器傳輸數據總歸需要連接,可不一樣的是websocket的連接需要程序員自己編碼維護, 而http的連接是web客戶端(或者http程序庫)和web伺服器幫你管理的,對於程序員而言, 我們不需要管理網路連接,只需要發送和接受數據即可。就是因為這個區別,http使用起來比websocket簡單不少。

表面上看,websocket也僅僅只是比http多了管理連接的部分,這不足以成為我們使用它的障礙,不就是多了個顯式的連接嗎,本程序員hold的住。可是在真實的項目開發中,業務邏輯千變萬化,開發人員能力又參差不齊,可能僅僅只是增加了這麼點複雜性,然而當這個複雜性扼住了項目要害之後,產生的副作用會是巨大的。就好比你用c寫一個helloworld程序和用java寫一個helloworld程序似乎沒感覺到多少差別,但是當要你們用這兩種語言去開發幾十萬行代碼的大項目之後,用c實現的成本和最終的項目質量可能根本就沒法和java比,這也是現今具有自動管理內存的虛擬機語言是如今編程領域中流砥柱的原因。

就拿我們開發的這款H5遊戲來說吧,使用websocket在開發的過程中一直沒什麼問題,因為現在不是十多年前,現在的電腦網路穩的一逼,連續幾個月都不會斷網,所以我們的遊戲在開發的過程中穩穩沒有因為網路原因而出現問題。 可是當遊戲在手機上跑的時候就不一樣啊,進個電梯會斷網, 上個廁所會斷網, 信號不好會斷網,網斷了,websocket連接也斷了,我們程序的做法是斷開後即去重連。重連沒什麼問題,也是正常的做法,可是重連完成需要發送身份驗證數據包,並等待響應,只有身份確認完畢後纔可以正常與伺服器進行交互,如果是http就不會有這些步驟, 斷網又有什麼關係,因為對http來說,伺服器和客戶端大多數時候本就是沒連接的。就是因為websocket多出了斷網重連的步驟,導致我們程序的複雜性增加,隨之而帶來的就是BUG 自然就變多了。在程序代碼中,複雜是產生問題的根源。

websocket還有一個問題,發出去的消息並不一定會響應。與之對應的http,發出去的請求必然會有一個響應,即使在伺服器崩潰的情況下也會有響應,比如連接超時,所以我們的程序必然可以根據響應的情況做出響應處理。可是websocket不行,它是非同步發送消息, 消息發出去以後,只能通過監聽伺服器的反饋來確定是否有回應,如果伺服器因為某種原因而沒有回應,那麼那些依賴回應的操作就會無法被觸發,整個程序執行流程終端,在用戶看來就是操作沒有反應了。而http則不會用這種情況,再不濟因為發送http請求(ajax)產生異常,也可以給個提示,不至於讓用戶覺得莫名其妙,但是websocket發個消息石沉大海那是常有的事情。

一言蔽之,使用http的項目更加健壯,使用websocket的項目更加脆弱。

然而, 在某些情況下卻必然要使用websocket,比如遊戲項目中玩家狀態的實時同步,比如伺服器發通知給客戶端,以及其他涉及伺服器主動發送消息給客戶端的情況,這些場景下我們唯一可用的也只有websocket,但是那些請求與響應一對一的場景下我們都應該使用http,即使項目中已經存在websocket。有更加合適的就一定不要去將就,否則將來受傷的還是我們自己。

以上內容主要討論websocket存在的一些問題,但是把websocket換成socket同樣合適,在原生手遊的開發上,能用http的地方就不要去用socket, 或者更寬泛的講,能用半雙工的地方就不要用全雙工。


推薦閱讀:
相關文章