日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如何使用网络库实现应用级消息收发

發布時間:2024/9/21 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何使用网络库实现应用级消息收发 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

為什么80%的碼農都做不了架構師?>>> ??

網絡客戶端ISocketClient和網絡會話ISocketSession都繼承了ISocketRemoteISocketRemote表示遠程通信,核心就是收發數據。
下面是ISocketRemote接口的主要實現

/// <summary>遠程通信Socket,僅具有收發功能</summary> public interface ISocketRemote : ISocket {#region 屬性/// <summary>遠程地址</summary>NetUri Remote { get; set; }/// <summary>通信開始時間</summary>DateTime StartTime { get; }/// <summary>最后一次通信時間,主要表示會話活躍時間,包括收發</summary>DateTime LastTime { get; }/// <summary>緩沖區大小</summary>Int32 BufferSize { get; set; }#endregion#region 發送/// <summary>發送數據</summary>/// <remarks>/// 目標地址由<seealso cref="Remote"/>決定/// </remarks>/// <param name="pk">數據包</param>/// <returns>是否成功</returns> Boolean Send(Packet pk);#endregion#region 接收/// <summary>接收數據。阻塞當前線程等待返回</summary>/// <returns></returns> Packet Receive();/// <summary>數據到達事件</summary>event EventHandler<ReceivedEventArgs> Received;/// <summary>消息到達事件</summary>event EventHandler<MessageEventArgs> MessageReceived;#endregion#region 數據包處理/// <summary>粘包處理接口</summary>IPacket Packet { get; set; }/// <summary>異步發送數據并等待響應</summary>/// <param name="pk"></param>/// <returns></returns>Task<Packet> SendAsync(Packet pk);/// <summary>發送消息并等待響應</summary>/// <param name="msg"></param>/// <returns></returns>Task<IMessage> SendAsync(IMessage msg);#endregion }

?



一、同步收發
一般小型網絡應用,或者個人學習程序,都會使用同步收發。
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連接。


因此,異步請求響應的架構設計,讓請求響應準確配對,支持并行請求,并且解決一切粘包問題!


應用級消息收發偽代碼:

var str = "{action:Open,args:{index:3},remark:打開3號燈}"; var client = new NetUri("tcp://127.0.0.1:1234").CreateRemote(); client.Packet = new DefaultPacket(); var rs = await client.SendAsync(str.GetBytes()); // rs = "{result:true,data:3號燈已打開}"

上面的DefaultPacket正是?新生命團隊標準網絡封包協議
請求響應包的頭部,都會增加4字節,Json字符串作為負載數據。
正是增加的這4字節,確保了請求響應的準確配對(序列號匹配),解決了粘包問題(頭部長度)


即使沒有默認封包DefualtPacket,上面代碼也是可以工作的,只是這樣就失去了準確配對和粘包拆分,要求業務層不能頻繁收發。


End.

轉載于:https://my.oschina.net/nnhy/blog/1591897

總結

以上是生活随笔為你收集整理的如何使用网络库实现应用级消息收发的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。