<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      NewLife.Net——管道處理器解決粘包

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

       

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

       

      一、管道處理器

      新建管道處理器項目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的編解碼器都可以在此使用。

      posted @ 2018-05-11 02:24  大石頭  閱讀(3641)  評論(11)    收藏  舉報
      主站蜘蛛池模板: 黄页网址大全免费观看| 淮阳县| 免费观看的av在线播放| 国产综合精品91老熟女| 欧美大bbbb流白水| 粉嫩小泬无遮挡久久久久久| 性色av不卡一区二区三区| 日本a在线播放| 国产午夜福利不卡在线观看| 日本免费精品| 一区二区三区精品偷拍| 天天躁夜夜踩很很踩2022| 日韩秘 无码一区二区三区| 九九热在线观看精品视频| 色爱综合激情五月激情| 香蕉EEWW99国产精选免费| 泗阳县| 69天堂人成无码免费视频| 亚洲精国产一区二区三区| 好硬好湿好爽好深视频| 欧美色丁香| 国内少妇人妻丰满av| 一区二区三区一级黄色片| 亚洲人妻系列中文字幕| 欧美视频专区一二在线观看| 亚洲国产色婷婷久久99精品91| 日韩人妻精品中文字幕| 久久这里有精品国产电影网| 亚洲欧美人成人让影院| 国产精品色内内在线播放| 国产精品视频第一第二区| 人妻少妇乱子伦精品无码专区电影| 日本韩国日韩少妇熟女少妇| 亚洲欧洲日产国码AV天堂偷窥| 日本丰满熟妇videossex一| 亚洲综合无码久久精品综合| 无码免费大香伊蕉在人线国产| 国精产品999国精产品官网| 亚洲激情一区二区三区视频| 强奷漂亮人妻系列老师| 国产普通话刺激视频在线播放|