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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

NewLife.Net——管道处理器解决粘包

發布時間:2025/4/5 asp.net 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 NewLife.Net——管道处理器解决粘包 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Tcp網絡編程,必須要解決的一個問題就是粘包,盡管解決辦法有很多,這里講一個比較簡單的方法。

?

老規矩,先上代碼:https://github.com/nnhy/NewLife.Net.Tests

?

一、管道處理器

新建管道處理器項目HandlerTest,源碼復制自第一節課的EchoTest項目,增加一個管道處理器類

class EchoHandler : Handler {public override Object Read(IHandlerContext context, Object message){var session = context.Session;var pk = message as Packet;session.WriteLog("收到:{0}", pk.ToStr());// 把收到的數據發回去 session.Send(pk);return null;} }

EchoHandler繼承自處理器基類Handler,重載Read方法,當網絡層收到數據包時,會調用該方法。

這里我們實現了Echo功能,并打印日志。返回null告知不再執行管道上的后續處理器。

?

既然有了處理器,第一節課中的MyNetServer就用不上啦,在TestServer中改回來標準的NetServer

// 實例化服務端,指定端口,同時在Tcp/Udp/IPv4/IPv6上監聽 var svr = new NetServer {Port = 1234,Log = XTrace.Log }; svr.Add<EchoHandler>(); svr.Start();

這里的svr.Add<EchoHandler>()把上面的處理器給注冊進去,大意就是由這個處理器來負責處理收到的網絡數據包。

?

跑起來服務端和客戶端看看效果:

可以看到,收發正常!

?

二、粘包的產生

真實應用場景中,不可能允許我們間隔1秒才發出一個網絡包,直接就不該有等待。連續發送多個數據包,就很容易產生粘包。

static void TestClient() {var uri = new NetUri("tcp://127.0.0.1:1234");//var uri = new NetUri("tcp://net.newlifex.com:1234");var client = uri.CreateRemote();client.Log = XTrace.Log;client.Received += (s, e) =>{XTrace.WriteLine("收到:{0}", e.Packet.ToStr());};client.Open();// 定時顯示性能數據_timer = new TimerX(ShowStat, client, 100, 1000);// 循環發送數據for (var i = 0; i < 5; i++){//Thread.Sleep(1000);var str = "你好" + (i + 1);client.Send(str);}//client.Dispose(); }

這里注釋了睡眠語句,讓它緊密發出5個數據包。注釋后面的Dispose,讓其有機會收到響應包。

跑起來看到,粘包了!!!

客戶端發送5次,服務端作為一個包給接收了,整體處理,然后返回給客戶端。

粘包的解決辦法很多,一般是加頭部長度或者分隔符,也有取巧的辦法直接設置NoDelay。

從使用上來講,相對可靠的做法是加頭部長度。因為除了多個包粘在一起,還可能出現一個包被拆成兩半,分別在前后兩個包里面。

?

三、普通粘包解法

我們加上頭部長度來解決解包問題。

修改一下服務端,增加一個處理器

static void TestServer() {// 實例化服務端,指定端口,同時在Tcp/Udp/IPv4/IPv6上監聽var svr = new NetServer{Port = 1234,Log = XTrace.Log};//svr.Add(new LengthFieldCodec { Size = 4 });svr.Add<StandardCodec>();svr.Add<EchoHandler>();// 打開原始數據日志var ns = svr.Server;ns.LogSend = true;ns.LogReceive = true;svr.Start();_server = svr;// 定時顯示性能數據_timer = new TimerX(ShowStat, svr, 100, 1000); }

StandardCodec處理器是新生命團隊標準封包。https://github.com/NewLifeX/X/tree/master/NewLife.Core/Net

其固定4字節作為頭部,其中后面兩個字節標識負載長度。

也可以使用LengthFieldCodec編碼器(如上注釋部分),并制定頭部加4字節作為長度。

編碼器順序非常重要,網絡層收到數據包以后,會從前向后走過每一個處理器;SendAsync/SendMessage發送消息時,會從后向前走過每一個過濾器,逆序。

?

客戶端也要增加相應過濾器

static void TestClient() {var uri = new NetUri("tcp://127.0.0.1:1234");//var uri = new NetUri("tcp://net.newlifex.com:1234");var client = uri.CreateRemote();client.Log = XTrace.Log;client.Received += (s, e) =>{var pk = e.Message as Packet;XTrace.WriteLine("收到:{0}", pk.ToStr());};//client.Add(new LengthFieldCodec { Size = 4 });client.Add<StandardCodec>();// 打開原始數據日志var ns = client;ns.LogSend = true;ns.LogReceive = true;client.Open();// 定時顯示性能數據_timer = new TimerX(ShowStat, client, 100, 1000);// 循環發送數據for (var i = 0; i < 5; i++){var str = "你好" + (i + 1);var pk = new Packet(str.GetBytes());client.SendAsync(pk);} }

發送函數改為SendAsync,原來的Send(Packet pk)會繞過管道處理器。

客戶端接收時,e.Message表示經過處理器處理得到的消息,e.Packet表示原始數據包。

?

同時,通過LogSend/LogReceive打開收發數據日志。

上圖效果,客戶端發出第5個包,頭部多了4個字節,其中07-00表示后續負載數據長度為7字節(NewLife)。

服務端先收到第一個包11字節,然后收到44字節,這是4個包粘在一起。

然后StandardCodec編碼器成功將其拆分成為4個,并依次通過EchoHandler。

到了客戶端這邊,也是后面4個粘在一起,并且也得到了正確拆分。

?

如果一個大包被拆分為幾個,StandardCodec也能緩沖合并,半包超過500~5000ms仍未能組合完整時將拋棄。

?

四、總結

借助管道處理器架構,我們輕易解決了粘包問題!

顯然,管道架構并非單純為了粘包問題而設計,它有著非常重要的意義,加解密、壓縮、各種協議處理,等等。

管道架構的設計,參考了Netty,因此大部分Netty的編解碼器都可以在此使用。

總結

以上是生活随笔為你收集整理的NewLife.Net——管道处理器解决粘包的全部內容,希望文章能夠幫你解決所遇到的問題。

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