TCP基于链接的协议,并且保证有序性。

但是,每个包的长度,需要明确,否则会发生粘包现象。

以下示例为一个自定义协议的例子,其中包含了拆包的内容。

所有的类:

协议类:

public class PersonProtocol {
private int length;
private byte[] content;
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public byte[] getContent() {
return content;
}
public void setContent(byte[] content) {
this.content = content;
}
}

解码器类:

public class PersonProtocolDecode extends ReplayingDecoder<Void> {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
System.out.println("decode invoke!");
  //拆包的内容如下:先获取长度,再根据获取的长度,获取到包内的内容。
int length = in.readInt();
byte[] content = new byte[length];
  //获取到内容
in.readBytes(content);
PersonProtocol personProtocol = new PersonProtocol();
personProtocol.setLength(length);
personProtocol.setContent(content);
out.add(personProtocol);
}
}

编码器类:

public class PersonProtocolEncode extends MessageToByteEncoder<PersonProtocol>{
@Override
protected void encode(ChannelHandlerContext ctx, PersonProtocol msg, ByteBuf out) throws Exception {
System.out.println("encode invoke!");
out.writeInt(msg.getLength());
out.writeBytes(msg.getContent());
//不需要flush的原因是,此时还是在jvm内部处理代码,并未涉及到io
}
}

服务器处理类:

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.nio.charset.Charset;
import java.util.UUID; public class ServerHandler extends SimpleChannelInboundHandler<PersonProtocol>{
private int count = 0;
@Override
protected void channelRead0(ChannelHandlerContext ctx, PersonProtocol msg) throws Exception {
System.out.println("接收到的消息长度:"+msg.getLength()
+",消息内容: "+new String(msg.getContent(), Charset.forName("utf-8")));
System.out.println("消息的次数:"+ ++count);
PersonProtocol result = new PersonProtocol();
UUID uuid = UUID.randomUUID();
byte[] count = uuid.toString().getBytes(Charset.forName("utf-8"));
System.out.println("发给客户端的数据为:长度"+count.length+",内容:"+uuid );
result.setLength(count.length);
result.setContent(count);
ctx.channel().writeAndFlush(result);
}
}

客户端处理类:

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.nio.charset.Charset; public class ClientHandler extends SimpleChannelInboundHandler<PersonProtocol>{
private int count = 0;
@Override
protected void channelRead0(ChannelHandlerContext ctx, PersonProtocol msg) throws Exception {
System.out.println("接收到的消息长度"+msg.getLength()
+",消息内容: "+new String(msg.getContent(), Charset.forName("utf-8")));
System.out.println("消息的次数:"+ ++count);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelActive");
String str = "你好吗?,我很好!,你好吗?我很好!";
for(int i = 0;i < str.split(",").length;i++){
String temp = str.split(",")[i];
System.out.println(temp+",i:"+i);
PersonProtocol pp = new PersonProtocol();
pp.setLength(temp.getBytes(Charset.forName("utf-8")).length);
pp.setContent(temp.getBytes(Charset.forName("utf-8")));
ctx.writeAndFlush(pp);
}
}
}

服务端启动类:

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel; public class NettyServer {
public static void main(String[] args) throws Exception{
EventLoopGroup bossGroup = new NioEventLoopGroup(1); //分发事件循环组
EventLoopGroup workGroup = new NioEventLoopGroup();//处理通道事件循环组
ServerBootstrap serverBootstrap = new ServerBootstrap();//初始化服务器
serverBootstrap.group(bossGroup,workGroup) //将两个循环组绑定到服务器
.channel(NioServerSocketChannel.class) //指定通道类型,当前使用NIO模式
.childHandler(new ChannelInitializer<SocketChannel>(){ //指定通道中的过滤器链
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new PersonProtocolDecode()); //解码器过滤
pipeline.addLast(new PersonProtocolEncode());//编码器
pipeline.addLast(new ServerHandler());//具体的业务处理,一般放在最后面
}
});
ChannelFuture channelFuture = serverBootstrap.bind(12345).sync();//绑定到本机的12345端口,等待同步处理结果
channelFuture.channel().closeFuture().sync();//阻塞等待closeFuture的返回,同步等待
bossGroup.shutdownGracefully();//优雅关闭
workGroup.shutdownGracefully();
}
}

客户端启动类:

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel; public class NettyClient {
public static void main(String[] args) throws Exception{
EventLoopGroup eventLoopGroup = new NioEventLoopGroup(1);
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class).
handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new PersonProtocolDecode());
pipeline.addLast(new PersonProtocolEncode());
pipeline.addLast(new ClientHandler());
}
});
ChannelFuture channelFuture = bootstrap.connect("localhost", 12345).sync();
channelFuture.channel().closeFuture().sync();//客户端阻塞,一直运行。
eventLoopGroup.shutdownGracefully();//优雅关闭
}
}

运行服务端,再运行客户端,即可完成测试。

TCP--粘包拆包,netty的解决方式的更多相关文章

  1. TCP粘包/拆包问题的解决

    TCP粘包拆包问题 一个完整的包可能被TCP拆分成多个包,或多个小包封装成一个大的数据包发送. 解决策略 消息定长,如果不够,空位补空格 在包尾增加回车换行符进行分割,例如FTP协议 将消息分为消息头 ...

  2. 第四章 TCP粘包/拆包问题的解决之道---4.1---

    4.1 TCP粘包/拆包 TCP是一个“流”协议,所谓流,就是没有界限的一串数据.TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可 ...

  3. 第四章 TCP粘包/拆包问题的解决之道---4.2--- 未考虑TCP粘包导致功能异常案例

    4.2 未考虑TCP粘包导致功能异常案例 如果代码没有考虑粘包/拆包问题,往往会出现解码错位或者错误,导致程序不能正常工作. 4.2.1 TimeServer 的改造 Class : TimeServ ...

  4. Netty使用LineBasedFrameDecoder解决TCP粘包/拆包

    TCP粘包/拆包 TCP是个”流”协议,所谓流,就是没有界限的一串数据.TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TC ...

  5. 《精通并发与Netty》学习笔记(13 - 解决TCP粘包拆包(一)概念及实例演示)

    一.粘包/拆包概念 TCP是一个“流”协议,所谓流,就是没有界限的一长串二进制数据.TCP作为传输层协议并不不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行数据包的划分,所以在业务上认 ...

  6. 深入学习Netty(5)——Netty是如何解决TCP粘包/拆包问题的?

    前言 学习Netty避免不了要去了解TCP粘包/拆包问题,熟悉各个编解码器是如何解决TCP粘包/拆包问题的,同时需要知道TCP粘包/拆包问题是怎么产生的. 在此博文前,可以先学习了解前几篇博文: 深入 ...

  7. Netty(三)TCP粘包拆包处理

    tcp是一个“流”的协议,一个完整的包可能会被TCP拆分成多个包进行发送,也可能把小的封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题. 粘包.拆包问题说明 假设客户端分别发送数据包D1和D ...

  8. Netty(二)——TCP粘包/拆包

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7814644.html 前面讲到:Netty(一)--Netty入门程序 主要内容: TCP粘包/拆包的基础知 ...

  9. TCP粘包/拆包(Netty权威指南)

    无论是服务端还是客户端,当我们读取或者发送消息的时候,都需要考虑TCP底层的粘包/拆包机制. TCP粘包/拆包 TCP是个“流”协议,所谓流,就是没有界限的一串数据.大家可以想想河里的流水,是连成一片 ...

  10. TCP粘包/拆包 ByteBuf和channel 如果没有Netty? 传统的多线程服务器,这个也是Apache处理请求的模式

    通俗地讲,Netty 能做什么? - 知乎 https://www.zhihu.com/question/24322387 谢邀.netty是一套在java NIO的基础上封装的便于用户开发网络应用程 ...

随机推荐

  1. GWAS这十年 | 10 Years of GWAS Discovery: Biology, Function, and Translation

    相关文章: A Unified Framework for Association Analysis with Multiple Related Phenotypes 太重要了,不得不单独拿出来分析一 ...

  2. SpringMVC:HandlerInterceptor log 日志

    springMVC:HandlerInterceptor拦截器添加系统日志(权限校验)代码收藏 - LinkcOne - CSDN博客https://blog.csdn.net/qq_22815337 ...

  3. 如何禁用Chrome浏览器的Flash

    使用Chrome浏览器时,经常会因为Flash而导致CPU占用过多,系统变慢.如果你常访问的网站很少用到的Flash或者页面上的Flash不是网站的核心功能,那么建议禁用Flash.禁用Flash的步 ...

  4. python脚本使用源码安装不同版本的python

    # coding=utf-8 import os import sys # 判断是否是root用户 if os.getuid() == 0: pass else: print('当前用户不是root用 ...

  5. linux非root用户安装4.0.14版本redis

    先到官网https://redis.io/download下安装包,现在最新是5.0.5版本,可惜点击下载后被windows禁了,那就下4版本的,往下看Other versions的Old(4.0), ...

  6. 【分布式一致性】etcd

    etcd: https://jimmysong.io/kubernetes-handbook/concepts/etcd.html 什么是 分布式一致性: http://thesecretliveso ...

  7. [转]Xmind 8 pro 软件破解版

    链接地址:https://blog.csdn.net/qq_16093323/article/details/80967867 作者博客:http://www.carrotchou.blog/

  8. vue骨架屏以及seo优化

    参考文档 vue骨架屏 https://blog.csdn.net/ly124100427/article/details/81168908 vue seo优化 1.SSR服务器渲染: 2.静态化: ...

  9. robot:根据条件主动判定用例失败或者通过

    场景: 当用例中的断言部分需要满足特定条件时才会执行,如果不满足条件时,可以主动判定该用例为passed状态,忽略下面的断言语句. 如上图场景,当每月1号时,表中才会生成上月数据,生成后数据不会再有改 ...

  10. Andrew Ng机器学习课程10补充

    Andrew Ng机器学习课程10补充 VC dimension 讲到了如果通过最小化训练误差,使用一个具有d个参数的hypothesis class进行学习,为了学习好,一般需要参数d的线性关系个训 ...