实例:Netty 处理 TCP协议数据分包问题

简介: 一、Netty解决TCP协议数据分包问题思路 我们知道通过TCP协议发送接收数据时,如果数据过大,接收到的数据会是分包的,比如:                                     +-----+-----+-----+          发送数据是: | ABC | DEF | GHI |                            

一、Netty解决TCP协议数据分包问题思路


我们知道通过TCP协议发送接收数据时,如果数据过大,接收到的数据会是分包的,比如:
                                     +-----+-----+-----+
         发送数据是: | ABC | DEF | GHI |
                            +-----+-----+-----+
         而我们想接受到的数据是: | ABCDEFGHI |
                    
该如何处理这种情况呢?Netty提供了一个专门处理TCP协议数据的Handler: LengthFieldBasedFrameDecoder它的原理是服务器端和客户端约定一个协议格式:数据包=协议长度+协议体

      --------------------------------数据包------------------------------

     | 协议长度部分(接收数据长度) | 协议体部分(要接收的数据)|

举个例子,假如我们的TCP客户端发送了10MB字节的数据,如何让Netty服务器一次就接收到这10MB数据呢?那就需要客户端告诉服务端我发送的数据大小是多少,即在发送的数据中加入一个“数据包长度”即可,上面提到的Handler就是用来和客户端约定这个协议格式的,它有几个参数,下面我介绍一下它的参数意义:
      int  maxFrameLength:定义接收数据包的最大长度,如果发送的数据包超过此值,则抛出异常;
     int  lengthFieldOffset:长度属性部分的偏移值,0表示长度属性位于数据包头部;
     int   lengthFieldLength:长度属性的字节长度,如果设置为4,就是我们用4个字节存放数据包的长度;
      int   lengthAdjustment:协议体长度调节值,修正信息长度,如果设置为4,那么解码时再向后推4个字节;
      int   initialBytesToStrip:跳过字节数,如我们想跳过长度属性部分。

二、实例-客户端发送10MB字节的数据,Netty服务端一次接收到全部10MB数据

客户端:定义一个消息体,用头部四个字节存放数据包长度

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;
	}
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,跳过头部协议长度四个字节
@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
				

			}


三、总结:客户端和服务端定义消息格式必须一致

目录
相关文章
|
8月前
|
存储 网络协议 前端开发
Netty服务端和客户端开发实例—官方原版
Netty服务端和客户端开发实例—官方原版
128 0
|
网络协议 物联网 开发者
NB-IoT 通信之 TCP 收发数据 | 学习笔记
快速学习 NB-IoT 通信之 TCP 收发数据
878 0
NB-IoT 通信之 TCP 收发数据 | 学习笔记
|
传感器 数据采集 JSON
RS232/RS485转4G DTU 上传基于Modbus协议的温湿度传感器数据到远程TCP服务器
RS232/RS485转4G DTU 上传基于Modbus协议的温湿度传感器数据到远程TCP服务器
583 0
RS232/RS485转4G DTU 上传基于Modbus协议的温湿度传感器数据到远程TCP服务器
|
4天前
|
网络协议 开发者 Python
tcp/ip模型中,帧是第几层的数据单元?
在网络通信的世界中,TCP/IP模型以其高效和可靠性而著称。这个模型是现代互联网通信的基石,它定义了数据在网络中如何被传输和接收。其中,一个核心的概念是数据单元的层级,特别是“帧”在这个模型中的位置。今天,我们就来说一下TCP/IP模型中帧的概念,以及它作为数据单元在哪一层中扮演着关键角色。
|
存储 监控 网络协议
搞了半天,终于弄懂了TCP Socket数据的接收和发送,太难
本文将从上层介绍Linux上的TCP/IP栈是如何工作的,特别是socket系统调用和内核数据结构的交互、内核和实际网络的交互。写这篇文章的部分原因是解释监听队列溢出(listen queue overflow)是如何工作的,因为它与我工作中一直在研究的一个问题相关。 建好的连接怎么工作 先从建好的连接开始介绍,稍后将解释新建连接是如何工作的。
522 0
搞了半天,终于弄懂了TCP Socket数据的接收和发送,太难
|
JSON 网络协议 Android开发
【Android 逆向】Android 逆向通用工具开发 ( Android 端远程命令工具 | Android 端可执行程序的 main 函数操作 | TCP 协议服务器建立 | 接收客户端数据 )
【Android 逆向】Android 逆向通用工具开发 ( Android 端远程命令工具 | Android 端可执行程序的 main 函数操作 | TCP 协议服务器建立 | 接收客户端数据 )
183 0
【Android 逆向】Android 逆向通用工具开发 ( Android 端远程命令工具 | Android 端可执行程序的 main 函数操作 | TCP 协议服务器建立 | 接收客户端数据 )
|
网络协议 Java
【Java 网络编程】TCP 传输机制 ( 数据拆分 | 排序 | 顺序发送 | 顺序组装 | 超时重发 )
【Java 网络编程】TCP 传输机制 ( 数据拆分 | 排序 | 顺序发送 | 顺序组装 | 超时重发 )
229 0
【Java 网络编程】TCP 传输机制 ( 数据拆分 | 排序 | 顺序发送 | 顺序组装 | 超时重发 )
|
网络协议
如何向通过TCP socket给服务器端发送的数据里注明自己的客户端地址
服务器端监听在端口8081后,客户端发起连接,客户端的port为54436.
如何向通过TCP socket给服务器端发送的数据里注明自己的客户端地址
|
网络协议
如何向通过TCP socket给服务器端发送的数据里注明自己的客户端地址
服务器端监听在端口8081后,客户端发起连接,客户端的port为54436.
如何向通过TCP socket给服务器端发送的数据里注明自己的客户端地址
Netty入门实例-Http服务
本文我们继续来实现Netty的第二个入门案例,一个Http服务。
Netty入门实例-Http服务