zoukankan      html  css  js  c++  java
  • 示例:Netty 处理 TCP数据分包协议

    一个、Netty解决TCP协议的数据分包的想法


    我们知道通过TCP协议发送接收数据时,假设数据过大。接收到的数据会是分包的。比方:
                                        +-----+-----+-----+
             发送数据是: | ABC | DEF | GHI |
                                +-----+-----+-----+
             而我们想接受到的数据是: | ABCDEFGHI |
                        
    该怎样处理这样的情况呢?Netty提供了一个专门处理TCP协议数据的Handler:LengthFieldBasedFrameDecoder它的原理是server端和client约定一个协议格式:数据包=协议长度+协议体

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

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

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

    二、实例-client发送10MB字节的数据。Netty服务端一次接收到所有10MB数据

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

    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
    				
    
    			}


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

    版权声明:本文博客原创文章。博客,未经同意,不得转载。

  • 相关阅读:
    mysql中in 做条件匹配 带逗号的字符串 数据异常解决
    [LeetCode] Kth Largest Element in a Stream 数据流中的第K大的元素
    [LeetCode] Binary Search 二分搜索法
    [LeetCode] Search in a Sorted Array of Unknown Size 在未知大小的有序数组中搜索
    [LeetCode] Insert into a Binary Search Tree 二叉搜索树中插入结点
    [LeetCode] Search in a Binary Search Tree 二叉搜索树中搜索
    [LeetCode] Design Circular Deque 设计环形双向队列
    [LeetCode] Design Circular Queue 设计环形队列
    [LeetCode] N-ary Tree Preorder Traversal N叉树的前序遍历
    [LeetCode] 589. N-ary Tree Postorder Traversal N叉树的后序遍历
  • 原文地址:https://www.cnblogs.com/yxwkf/p/4754950.html
Copyright © 2011-2022 走看看