Netty之解決TCP粘包拆包(設定訊息邊界)
1、什麼是粘包/拆包
一般所謂的TCP粘包是在一次接收資料不能完全地體現一個完整的訊息資料。TCP通訊為何存在粘包呢?主要原因是TCP是以流的方式來處理資料,再加上網路上MTU的往往小於在應用處理的訊息資料,所以就會引發一次接收的資料無法滿足訊息的需要,導致粘包的存在。處理粘包的唯一方法就是制定應用層的資料通訊協議,通過協議來規範現有接收的資料是否滿足訊息資料的需要。
2、解決辦法
2.1、訊息定長,報文大小固定長度,不夠空格補全,傳送和接收方遵循相同的約定,這樣即使粘包了通過接收方程式設計實現獲取定長報文也能區分。
2.2、包尾新增特殊分隔符,例如每條報文結束都添加回車換行符(例如FTP協議)或者指定特殊字元作為報文分隔符,接收方通過特殊分隔符切分報文區分。
2.3、將訊息分為訊息頭和訊息體,訊息頭中包含表示資訊的總長度(或者訊息體長度)的欄位
3、Netty中提供了DelimiterBasedFrameDecoder解碼器可以幫助我們輕鬆實現第二種解決方案,、包尾新增特殊分隔符。
4、加入DelimiterBasedFrameDecoder解碼器
4.1 在服務端,加入DelimiterBasedFrameDecoder解碼器
4.2 在客戶端,加入DelimiterBasedFrameDecoder解碼器
5、用到的分隔符的定義
6、服務端的實現public class ConstValue { public final static String FUHAO = "$_"; }
7、服務端Handler的實現import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.DelimiterBasedFrameDecoder; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; public class Server { public void bind(int port) throws Exception { // 伺服器執行緒組 用於網路事件的處理 一個用於伺服器接收客戶端的連線 // 另一個執行緒組用於處理SocketChannel的網路讀寫 EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { // NIO伺服器端的輔助啟動類 降低伺服器開發難度 ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class)// 類似NIO中serverSocketChannel .option(ChannelOption.SO_BACKLOG, 1024)// 配置TCP引數 .option(ChannelOption.SO_BACKLOG, 1024) // 設定tcp緩衝區 .option(ChannelOption.SO_SNDBUF, 32 * 1024) // 設定傳送緩衝大小 .option(ChannelOption.SO_RCVBUF, 32 * 1024) // 這是接收緩衝大小 .option(ChannelOption.SO_KEEPALIVE, true) // 保持連線 .childHandler(new ChildChannelHandler());// 最後繫結I/O事件的處理類 // 處理網路IO事件 // 伺服器啟動後 繫結監聽埠 同步等待成功 主要用於非同步操作的通知回撥 回撥處理用的ChildChannelHandler ChannelFuture f = serverBootstrap.bind(port).sync(); System.out.println("Server啟動"); // 等待服務端監聽埠關閉 f.channel().closeFuture().sync(); } finally { // 優雅退出 釋放執行緒池資源 bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); System.out.println("伺服器優雅的釋放了執行緒資源..."); } } /** * 網路事件處理器 */ private class ChildChannelHandler extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new StringEncoder()); // 設定特殊分隔符 ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes()); ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, buf)); // 設定字串形式的解碼 ch.pipeline().addLast(new StringDecoder()); ch.pipeline().addLast(new ServerHandler()); } } public static void main(String[] args) throws Exception { int port = 9998; new Server().bind(port); } }
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
public class ServerHandler extends ChannelHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
String request = (String) msg;
System.out.println("Server :" + msg);
String response = request;
ctx.writeAndFlush(response + ConstValue.FUHAO);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable t)
throws Exception {
ctx.close();
}
}
8、客戶端的實現
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class Client {
/**
* 連線伺服器
*
* @param port
* @param host
* @throws Exception
*/
public void connect(int port, String host) throws Exception {
// 配置客戶端NIO執行緒組
EventLoopGroup group = new NioEventLoopGroup();
try {
// 客戶端輔助啟動類 對客戶端配置
Bootstrap b = new Bootstrap();
b.group(group)//
.channel(NioSocketChannel.class)//
.option(ChannelOption.TCP_NODELAY, true)//
.handler(new MyChannelHandler());//
// 非同步連結伺服器 同步等待連結成功
ChannelFuture f = b.connect(host, port).sync();
// 等待連結關閉
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
System.out.println("客戶端優雅的釋放了執行緒資源...");
}
}
/**
* 網路事件處理器
*/
private class MyChannelHandler extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringEncoder());
// 設定特殊分隔符
ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, buf));
ch.pipeline().addLast(new StringDecoder());
// 客戶端的處理器
ch.pipeline().addLast(new ClientHandler());
}
}
public static void main(String[] args) throws Exception {
new Client().connect(9998, "127.0.0.1");
}
}
9、客戶端Handler的實現
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
public class ClientHandler extends ChannelHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// 客戶端連線成功,給服務端傳送資料
ctx.channel().writeAndFlush("aaaaabbbbb" + ConstValue.FUHAO);
// 增加空格,達到定長
ctx.channel().writeAndFlush("ccccccc " + ConstValue.FUHAO);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
String response = (String) msg;
System.out.println("Client: " + response);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
ctx.close();
}
}
相關推薦
【轉】Netty之解決TCP粘包拆包(自定義協議)
https://www.cnblogs.com/sidesky/p/6913109.html 1、什麼是粘包/拆包 一般所謂的TCP粘包是在一次接收資料不能完全地體現一個完整的訊息資料。TCP通訊為何存在粘包呢?主要原因是TCP是以流的方
Netty之解決TCP粘包拆包(設定訊息邊界)
1、什麼是粘包/拆包 一般所謂的TCP粘包是在一次接收資料不能完全地體現一個完整的訊息資料。TCP通訊為何存在粘包呢?主要原因是TCP是以流的方式來處理資料,再加上網路上MTU的往往小於在應用處理的訊息資料,所以就會引發一次接收的資料無法滿足訊息的需要,
Netty之解決TCP粘包拆包(自定義協議)
1、什麼是粘包/拆包 一般所謂的TCP粘包是在一次接收資料不能完全地體現一個完整的訊息資料。TCP通訊為何存在粘包呢?主要原因是TCP是以流的方式來處理資料,再加上網路上MTU的往往小於在應用處理的訊息資料,所以就會引發一次接收的資料無法滿足訊息的需要,導
結合RPC框架通訊談 netty如何解決TCP粘包問題
0.起因 因為自己造一個RPC框架的輪子時,需要解決TCP的粘包問題,特此記錄,希望方便他人。這是我寫的RPC框架的 GitHub地址 github.com/yangzhenkun… 歡迎star,fork。已經寫了多篇文章對這個框架的原理進行說明。對原理有興趣的歡迎交流。 1.什麼是粘包 1.1 什麼
netty權威指南學習筆記四——TCP粘包/拆包之粘包問題解決
方法 pan 對象 protect row 學習 ddl .get font 發生了粘包,我們需要將其清晰的進行拆包處理,這裏采用LineBasedFrameDecoder來解決 LineBasedFrameDecoder的工作原理是它依次遍歷ByteBuf中的可讀字節
Netty 之 TCP粘包拆包基本解決方案
上個小節我們淺析了在Netty的使用的時候TCP的粘包和拆包的現象,Netty對此問題提供了相對比較豐富的解決方案 Netty提供了幾個常用的解碼器,幫助我們解決這些問題,其實上述的粘包和拆包的問題,歸根結底的解決方案就是傳送端給遠端端一個標記,告訴遠端端,
一起學Netty(七)之 TCP粘包拆包基本解決方案
上個小節我們淺析了在Netty的使用的時候TCP的粘包和拆包的現象,Netty對此問題提供了相對比較豐富的解決方案 Netty提供了幾個常用的解碼器,幫助我們解決這些問題,其實上述的粘包和拆包的問題,歸根結底的解決方案就是傳送端給遠端端一個標記,告訴遠端端,每個資訊的結束
Netty學習之路(五)-TCP粘包/拆包問題
TCP是個“流協議”,所謂流,就是沒有界限的一串資料。TCP底層並不瞭解上層業務資料的具體含義,它會根據TCP緩衝區的實際情況進行包的劃分,所以一個完整的包可能會被TCP拆分成多個包進行傳送,也有可能吧多個小的包封裝成一個大的資料包傳送,這就是TCP粘包和拆包問題。 TCP粘包/拆包產生
Netty學習之分隔符解決TCP粘包
package com.phei.netty.s20160424; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.ne
Netty精粹之TCP粘包拆包問題
粘包拆包問題是處於網路比較底層的問題,在資料鏈路層、網路層以及傳輸層都有可能發生。我們日常的網路應用開發大都在傳輸層進行,由於UDP有訊息保護邊界,不會發生這個問題,因此這篇文章只討論發生在傳輸層的TCP粘包拆包問題。 什麼是粘包、拆包? 對於什麼是粘包、拆包問題,
【Netty4.x】Netty TCP粘包/拆包問題的解決辦法(二)
一、什麼是TCP粘包/拆包 如圖所示,假如客戶端分別傳送兩個資料包D1和D2給服務端,由於服務端一次讀取到的位元組數是不確定的,故可能存在以下4中情況:第一種情況:Server端分別讀取到D1和D2,沒有產生粘包和拆包的情況。第二種情況:Server端一次接收到兩個資料包,
一起學Netty(六)之 TCP粘包拆包場景
TCP程式設計底層都有粘包和拆包機制,因為我們在C/S這種傳輸模型下,以TCP協議傳輸的時候,在網路中的byte其實就像是河水,TCP就像一個搬運工,將這流水從一端轉送到另一端,這時又分兩種情況: 1)如果客戶端的每次製造的水比較多,也就是我們常說的客戶端給的包比較大,TC
Netty中LineBasedFrameDecoder解碼器使用與分析:解決TCP粘包問題
ring public xpl cep ctx new 綁定端口 註意 相關 [toc] Netty中LineBasedFrameDecoder解碼器使用與分析:解決TCP粘包問題 上一篇文章《Netty中TCP粘包問題代碼示例與分析》演示了使用了時間服務器的例子演示了T
TCP粘包拆包基本解決方案
scu fonts println mar 是我 perf throws 自己 切割 上個小節我們淺析了在Netty的使用的時候TCP的粘包和拆包的現象,Netty對此問題提供了相對比較豐富的解決方案 Netty提供了幾個常用的解碼器,幫助我們解決這些問題,其實上述
netty學習筆記一:TCP粘包拆包
min -s 原因 兩個 image 分享 技術 ima 選項 什麽是TCP拆包粘包 假設客戶端發送了2條消息M1,M2。可能會出現以下幾種情況。 1、服務端正常接收到M1,M2這兩條消息。 2、服務端一次接收到了2個數據包,M1和M2粘合在一起,這時候就被稱為TCP粘包
Netty權威指南_札記04_TCP粘包/拆包問題解決
文章目錄 Netty權威指南_札記04_TCP粘包/拆包問題解決 1. TCP粘包/拆包 1.1 TCP粘包/拆包問題說明 1.2 TCP粘包/拆包發生的原因 1.3 粘包問題解決策略
Unity C# 自定義TCP傳輸協議以及封包拆包、解決粘包問題(網路應用層協議)
本文只是初步實現了一個簡單的基於TCP的自定協議,更為複雜的協議可以根據這種方式去擴充套件。 網路應用層協議,通俗一點的講,它是一種基於socket傳輸的由傳送方和接收方事先協商好的一種訊息包組成結構,主要由訊息頭和訊息體組成。 眾所周知,基於socket的資訊互動有兩
TCP粘包/拆包--利用DelimiterBasedFrameDecoder解決TCP粘包問題
前面我們介紹了利用LineBasedFrameDecoder解決TCP的粘包/拆包的問題, 現在我們繼續介紹Netty的另外一種解碼器--DelemiterBasedFrameDecoder。 1. DelimiterBasedFrameDecoder服務端開發 EchoS
Netty中處理TCP粘包和拆包
什麼是粘包和拆包 TCP是個”流”協議,流其實就是沒有界限的一串資料。 TCP底層中並不瞭解上層業務資料的具體含義,它會根據TCP緩衝區的實際情況進行包劃分,所以在TCP中就有可能一個完整地包會被TCP拆分成多個包,也有可能吧多個小的包封裝成一個大的資料包傳
【Netty入門】解決TCP粘包/分包的例項
回顧TCP粘包/分包問題的解決方法 1.訊息定長 2.在包尾都增加特殊字元進行分割 3.將訊息分為訊息頭和訊息體 針對這三種方法,下面我會分別舉例驗證 FixedLengthFrameDecoder類 對應第一種解決方法:訊息定長 (1)例1: