实例:Netty 处理 TCP协议数据分包问题
2015-04-07 10:09
459 查看
一、Netty解决TCP协议数据分包问题思路
我们知道通过TCP协议发送接收数据时,如果数据过大,接收到的数据会是分包的,比如:
+-----+-----+-----+
发送数据是: | ABC | DEF | GHI |
+-----+-----+-----+
而我们想接受到的数据是: | ABCDEFGHI |
该如何处理这种情况呢?Netty提供了一个专门处理TCP协议数据的Handler:LengthFieldBasedFrameDecoder ,它的原理是服务器端和客户端约定一个协议格式:数据包=协议长度+协议体
--------------------------------数据包------------------------------
| 协议长度部分(接收数据长度) | 协议体部分(要接收的数据)|
[align=left]
[/align]
[align=left]举个例子,假如我们的TCP客户端发送了10MB字节的数据,如何让Netty服务器一次就接收到这10MB数据呢?那就需要客户端告诉服务端我发送的数据大小是多少,即在发送的数据中加入一个“数据包长度”即可,上面提到的Handler就是用来和客户端约定这个协议格式的,它有几个参数,下面我介绍一下它的参数意义:[/align]
[align=left] int maxFrameLength:定义接收数据包的最大长度,如果发送的数据包超过此值,则抛出异常;[/align]
[align=left] int lengthFieldOffset:长度属性部分的偏移值,0表示长度属性位于数据包头部;[/align]
int lengthFieldLength:长度属性的字节长度,如果设置为4,就是我们用4个字节存放数据包的长度;
int lengthAdjustment:协议体长度调节值,修正信息长度,如果设置为4,那么解码时再向后推4个字节;
int initialBytesToStrip:跳过字节数,如我们想跳过长度属性部分。
二、实例-客户端发送10MB字节的数据,Netty服务端一次接收到全部10MB数据
客户端:定义一个消息体,用头部四个字节存放数据包长度
[java]
view plaincopy
public byte[] send(byte[] sendData) throws UnknownHostException, IOException {
Socket socket = new Socket(serverIp, serverPort);
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
byte resultArray[] = null;
try {
// 定义一个发送消息协议格式:|--header:4 byte--|--content:10MB--|
// 获取一个4字节长度的协议体头
byte[] dataLength = intToByteArray(4, sendData.length);
// 和请求的数据组成一个请求数据包
byte[] requestMessage = combineByteArray(dataLength, sendData);
//发送数据-------------------------------
os.write(requestMessage);
os.flush();
//接收数据-------------------------------
resultArray = IOUtils.toByteArray(is);
} catch (Exception e) {
e.printStackTrace();
} finally {
os.close();
is.close();
socket.close();
}
return resultArray;
}
[java]
view plaincopy
private static byte[] intToByteArray(int byteLength, int intValue) {
return ByteBuffer.allocate(byteLength).putInt(intValue).array();
}
private static byte[] combineByteArray(byte[] array1, byte[] array2) {
byte[] combined = new byte[array1.length + array2.length];
System.arraycopy(array1, 0, combined, 0, array1.length);
System.arraycopy(array2, 0, combined, array1.length, array2.length);
return combined;
}
Netty服务端:定义一个LengthFieldBasedFrameDecoder(1024*1024*1024, 0, 4,0,4)),最大数据量是1GB,长度属性位于数据包头部,占4个字节,协议体调节值为0,跳过头部协议长度四个字节
[java]
view plaincopy
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("framedecoder",new LengthFieldBasedFrameDecoder(1024*1024*1024, 0, 4,0,4));
pipeline.addLast(new TCPServiceHandler());// 处理业务Handler
}
三、总结:客户端和服务端定义消息格式必须一致
我们知道通过TCP协议发送接收数据时,如果数据过大,接收到的数据会是分包的,比如:
+-----+-----+-----+
发送数据是: | ABC | DEF | GHI |
+-----+-----+-----+
而我们想接受到的数据是: | ABCDEFGHI |
该如何处理这种情况呢?Netty提供了一个专门处理TCP协议数据的Handler:LengthFieldBasedFrameDecoder ,它的原理是服务器端和客户端约定一个协议格式:数据包=协议长度+协议体
--------------------------------数据包------------------------------
| 协议长度部分(接收数据长度) | 协议体部分(要接收的数据)|
[align=left]
[/align]
[align=left]举个例子,假如我们的TCP客户端发送了10MB字节的数据,如何让Netty服务器一次就接收到这10MB数据呢?那就需要客户端告诉服务端我发送的数据大小是多少,即在发送的数据中加入一个“数据包长度”即可,上面提到的Handler就是用来和客户端约定这个协议格式的,它有几个参数,下面我介绍一下它的参数意义:[/align]
[align=left] int maxFrameLength:定义接收数据包的最大长度,如果发送的数据包超过此值,则抛出异常;[/align]
[align=left] int lengthFieldOffset:长度属性部分的偏移值,0表示长度属性位于数据包头部;[/align]
int lengthFieldLength:长度属性的字节长度,如果设置为4,就是我们用4个字节存放数据包的长度;
int lengthAdjustment:协议体长度调节值,修正信息长度,如果设置为4,那么解码时再向后推4个字节;
int initialBytesToStrip:跳过字节数,如我们想跳过长度属性部分。
二、实例-客户端发送10MB字节的数据,Netty服务端一次接收到全部10MB数据
客户端:定义一个消息体,用头部四个字节存放数据包长度
[java]
view plaincopy
public byte[] send(byte[] sendData) throws UnknownHostException, IOException {
Socket socket = new Socket(serverIp, serverPort);
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
byte resultArray[] = null;
try {
// 定义一个发送消息协议格式:|--header:4 byte--|--content:10MB--|
// 获取一个4字节长度的协议体头
byte[] dataLength = intToByteArray(4, sendData.length);
// 和请求的数据组成一个请求数据包
byte[] requestMessage = combineByteArray(dataLength, sendData);
//发送数据-------------------------------
os.write(requestMessage);
os.flush();
//接收数据-------------------------------
resultArray = IOUtils.toByteArray(is);
} catch (Exception e) {
e.printStackTrace();
} finally {
os.close();
is.close();
socket.close();
}
return resultArray;
}
[java]
view plaincopy
private static byte[] intToByteArray(int byteLength, int intValue) {
return ByteBuffer.allocate(byteLength).putInt(intValue).array();
}
private static byte[] combineByteArray(byte[] array1, byte[] array2) {
byte[] combined = new byte[array1.length + array2.length];
System.arraycopy(array1, 0, combined, 0, array1.length);
System.arraycopy(array2, 0, combined, array1.length, array2.length);
return combined;
}
Netty服务端:定义一个LengthFieldBasedFrameDecoder(1024*1024*1024, 0, 4,0,4)),最大数据量是1GB,长度属性位于数据包头部,占4个字节,协议体调节值为0,跳过头部协议长度四个字节
[java]
view plaincopy
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("framedecoder",new LengthFieldBasedFrameDecoder(1024*1024*1024, 0, 4,0,4));
pipeline.addLast(new TCPServiceHandler());// 处理业务Handler
}
三、总结:客户端和服务端定义消息格式必须一致
相关文章推荐
- 实例:Netty 处理 TCP协议数据分包问题
- 示例:Netty 处理 TCP数据分包协议
- netty 数据分包、组包、粘包处理机制(一)
- Go语言中Tcp协议粘包问题处理
- netty 数据分包、组包、粘包处理机制(二)
- Netty 快速入门系列 - Chapter 7 数据包协议【第十六讲】数据传输问题
- 通信(Netty、Mina2)【通信粘包的处理】、【数据协议】、【网络系统的安全性】
- Go语言中Tcp协议粘包问题处理
- netty 数据分包、组包、粘包处理机制(二)
- netty 数据分包、组包、粘包处理机制
- java netty使用DelimiterBasedFrameDecoder处理tcp粘包问题
- netty源码分析(二十五)Netty自定义协议与TCP粘包拆包问题解决之道
- 转自美团技术:机器学习中的数据清洗与特征处理综述&实例详解机器学习如何解决问题
- netty 数据分包、组包、粘包处理
- Netty5用户手册之五:netty中流数据的传输处理问题
- netty 数据分包、组包、粘包处理机制(一)
- 通信(Netty、Mina2)【通信粘包的处理】、【数据协议】、【网络系统的安全性】
- tcp 数据传输实例测试
- ORACLE10G 在 LINUX环境下日志损坏后修复并重新处理数据(TEST5实例)
- 如何处理ODBC中EXCEL驱动读取EXCEL文件中字段长度大于255字符时出现的"数据截断"问题.