如何使用网络库实现应用级消息收发
為什么80%的碼農都做不了架構師?>>> ??
網絡客戶端ISocketClient和網絡會話ISocketSession都繼承了ISocketRemoteISocketRemote表示遠程通信,核心就是收發數據。
下面是ISocketRemote接口的主要實現
?
一、同步收發
一般小型網絡應用,或者個人學習程序,都會使用同步收發。
Send(xxx);
var buf = Receive();
這樣向對服務端發一個數據包,然后同步阻塞等待接收一個響應數據。
同步收發最大的優點就是簡單,容易理解;
最大的缺點是性能極其底下,并且很大的幾率會失敗拋出異常,特別是離開本機或者局域網以后。
除非網絡很干凈,客戶端服務端只進行很簡單的通信,否則出錯崩潰就是家常便飯!
并且,這個階段的工程師,一般認為只能客戶端向服務端發數據,而不知道服務端可以主動向客戶端發數據。
因此,15年經驗表明,同步收發根本不適合做產品級應用!
二、事件驅動
中大型網絡應用,一般采用事件驅動,特別是多并發服務端。
不管是APM還是SAEA,絕大多數網絡框架都會包裝成為事件,或者路由分發架構。
正如前文接口圖黃色箭頭所示,事件驅動一般用法:
client.Received += OnReceive;
client.Send(xxx);
先建立接收事件,然后發送數據,如果對方有響應,就會觸發OnReceive函數,對響應結果進行處理。
事件驅動(包括路由分發)是當下網絡框架主流,占比超過70%
幾乎所有框架都會在此之外再包裝一層,Send一個業務對象,內部序列化為數據后發出,OnReceive后反序列化得到業務對象,返回給上層。
事件驅動跟同步業務需求是相背而行的。
如果業務需要向服務端發送一個請求,然后等待響應結果,那么事件驅動甚至還不如同步操作好用!
一般做法是Send里面做堵塞等待,然后OnReceive里面做攔截。
這也是事件驅動無法進一步擴大比例的根本原因。
事件驅動很好很強大,只是特別不適應業務上的同步操作需求!
三、異步請求響應
近20年的軟件發展史,無一例外等同于Web發展史。
除了技術的發展,Web思維影響了幾乎所有軟件工程師。哪怕初學者,也很清楚HTTP是請求響應模型。在Web開發里面,所有的業務都要基于請求與響應。
于是我們網絡庫有了第三種選擇。(前文接口圖紫色箭頭)
Task<Packet> SendAsync(Packet pk);
Task<IMessage> SendAsync(IMessage msg);
event EventHandler<MessageEventArgs> MessageReceived;
異步發送SendAsync,可以像事件模型那樣在MessageReceived里面處理,也可以 var rs = await SendAsync(pk); 把異步轉為同步操作,滿足同步業務需求。
更為重要的是,SendAsync支持單連接通道并行多異步請求!
也就是說,在一個網絡連接上,第一個請求的響應還沒有收到之前,業務邏輯可以連續發出更多的請求,不管這些請求的響應包先后順序以后,網絡庫都能夠準確配對,讓await SendAsync得到正確的結果。
這就解決了一個極為常見的問題,一個業務應用里面,可能多個線程需要向服務端請求數據,而傳統做法只能是加鎖,在第一個請求響應完成之前,阻塞其它請求。
實際上,HTTP 1.0/1.1正是傳統做法,前一個請求完成之前,不能發起新的請求,導致瀏覽器不得不建立多個Tcp連接。
因此,異步請求響應的架構設計,讓請求響應準確配對,支持并行請求,并且解決一切粘包問題!
應用級消息收發偽代碼:
上面的DefaultPacket正是?新生命團隊標準網絡封包協議
請求響應包的頭部,都會增加4字節,Json字符串作為負載數據。
正是增加的這4字節,確保了請求響應的準確配對(序列號匹配),解決了粘包問題(頭部長度)
即使沒有默認封包DefualtPacket,上面代碼也是可以工作的,只是這樣就失去了準確配對和粘包拆分,要求業務層不能頻繁收發。
End.
轉載于:https://my.oschina.net/nnhy/blog/1591897
總結
以上是生活随笔為你收集整理的如何使用网络库实现应用级消息收发的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java多线程相关的常用接口
- 下一篇: xmodmap: unable to