问题描述

比如要发ABC DEFG HIJK 这一串数据,其中ABC是一个包,DEFG是一个包,HIJK是一个包。由于TCP是基于流发送的,所以有可能出现ABCD EFGH 这种情况,那么ABC和D就粘包了,DEFG被拆开了。

解决方案

1、消息定长,例如报文大小控制为200,如果不够就空位补全

2、在包结尾加特殊字符进行分割,如$_

3、消息分为消息头和消息体,在消息中包含消息长度等字段,然后进行消息逻辑处理。

分隔符方案

服务端

import java.nio.ByteBuffer;

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.FixedLengthFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder; public class Server { public static void main(String[] args) throws Exception{
//1 创建2个线程,一个是负责接收客户端的连接。一个是负责进行数据传输的
EventLoopGroup pGroup = new NioEventLoopGroup();
EventLoopGroup cGroup = new NioEventLoopGroup(); //2 创建服务器辅助类
ServerBootstrap b = new ServerBootstrap();
b.group(pGroup, cGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.option(ChannelOption.SO_SNDBUF, 32*1024)
.option(ChannelOption.SO_RCVBUF, 32*1024)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
//设置特殊分隔符
ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, buf));
//设置字符串形式的解码
sc.pipeline().addLast(new StringDecoder());
sc.pipeline().addLast(new ServerHandler());
}
}); //4 绑定连接
ChannelFuture cf = b.bind(8765).sync(); //等待服务器监听端口关闭
cf.channel().closeFuture().sync();
pGroup.shutdownGracefully();
cGroup.shutdownGracefully(); } }
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext; public class ServerHandler extends ChannelHandlerAdapter { @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println(" server channel active... ");
} @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
String request = (String)msg;
System.out.println("Server :" + msg);
String response = "服务器响应:" + msg + "$_";
ctx.writeAndFlush(Unpooled.copiedBuffer(response.getBytes()));
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { } @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable t) throws Exception {
ctx.close();
} }

客户端

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.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.FixedLengthFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder; public class Client { public static void main(String[] args) throws Exception { EventLoopGroup group = new NioEventLoopGroup(); Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
//
ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, buf));
sc.pipeline().addLast(new StringDecoder());
sc.pipeline().addLast(new ClientHandler());
}
}); ChannelFuture cf = b.connect("127.0.0.1", 8765).sync(); cf.channel().writeAndFlush(Unpooled.wrappedBuffer("bbbb$_".getBytes()));
cf.channel().writeAndFlush(Unpooled.wrappedBuffer("cccc$_".getBytes())); //等待客户端端口关闭
cf.channel().closeFuture().sync();
group.shutdownGracefully(); }
}
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil; public class ClientHandler extends ChannelHandlerAdapter{ @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("client channel active... ");
} @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
String response = (String)msg;
System.out.println("Client: " + response);
} finally {
ReferenceCountUtil.release(msg);
}
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
} }
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil; public class ClientHandler extends ChannelHandlerAdapter{ @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("client channel active... ");
} @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
String response = (String)msg;
System.out.println("Client: " + response);
} finally {
ReferenceCountUtil.release(msg);
}
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
} }

架构师养成记--20.netty的tcp拆包粘包问题的更多相关文章

  1. 架构师养成记--19.netty

    一.Netty初步 为什么选择Netty? 和NIO比较,要实现一个通信要简单得很多,性能很好.分布式消息中间件.storm.Dubble都是使用Netty作为底层通信. Netty5.0要求jdk1 ...

  2. 架构师养成记--21.netty编码解码

    背景 作为网络传输框架,免不了哟啊传输对象,对象在传输之前就要序列化,这个序列化的过程就是编码过程.接收到编码后的数据就需要解码,还原传输的数据. 代码 工厂类 import io.netty.han ...

  3. TCP拆包粘包之分隔符解码器

    TCP以流的方式进行数据传输,上层的应用协议为了对消息进行区分,往往采用如下4种方式. (1)消息长度固定,累计读取到长度总和为定长LEN的报文后,就认为读取到了一个完整的消息:将计数器置位,重新开始 ...

  4. tomcat Http11NioProtocol如何解析http请求及如何解决TCP拆包粘包

    前言 tomcat是常用的Web 应用服务器,目前国内有很多文章讲解了tomcat架构,请求流程等,但是没有如何解析http请求及如何解决TCP粘包拆包,所以这篇文章的目的就是介绍这块内容,一下内容完 ...

  5. 使用Netty如何解决拆包粘包的问题

    首先,我们通过一个DEMO来模拟TCP的拆包粘包的情况:客户端连续向服务端发送100个相同消息.服务端的代码如下: AtomicLong count = new AtomicLong(0); NioE ...

  6. 架构师养成记--22.客户端与服务器端保持连接的解决方案,netty的ReadTimeoutHandler

    概述 保持客户端与服务器端连接的方案常用的有3种 1.长连接,也就是客户端与服务器端一直保持连接,适用于客户端比较少的情况. 2.定时段连接,比如在某一天的凌晨建立连接,适用于对实时性要求不高的情况. ...

  7. 架构师养成记--11.Executor概述

    常用方法 Executors.newFiexdPool(int nThreads);固定线程数量的线程池: Executors.newSingleThreadExecutor();单个线程的线程池: ...

  8. 架构师养成记--10.master-worker模式

    master-worker模式是一种并行计算模式,分为master进程和worker进程两个部分,master是担任总管角色,worker才是执行具体任务的地方. 总体流程应该是这样的: 具体一点,代 ...

  9. 架构师养成记--3.synchronized细节问题

    一.synchronized有锁重入的特点,某个线程得到对象的锁后,再次请求此对象可以再次得到改对象的锁.如下示例,在method1中调用method2,在method2中调用method3,而met ...

随机推荐

  1. Jenkins使用FTP进行一键部署及回滚2(Windows)(项目实践)

     转载:http://www.cnblogs.com/EasonJim/p/6295372.html Jenkins使用FTP进行一键部署及回滚2(Windows)(项目实践) 前提: 这一篇是继上一 ...

  2. javascript+php实现根据用户时区显示当地时间的方法

    本文实例讲述了javascript+php实现根据用户时区显示当地时间的方法.分享给大家供大家参考.具体如下: 在跨时区应用中会用到下面代码,这是以前写的一段代码. 服务器保存相关时间配置,保存形式为 ...

  3. Openssl dgst命令

    一.简介 消息摘要可以对任意长度的消息产生固定长度(16或20个字节)的信息摘要,理论基于单向HASH函数,根据消息摘要无法恢复出原文,所以是安全的:消息原文和消息摘要是一一对应的,所以又被称作指纹. ...

  4. 关于java项目中的.classpath文件:

    Classpath是Java中的重要概念: 它描述了Java虚拟机在运行一个Class时在哪些路径中加载要运行的类以及运行的类要用到的类 简单的说,就是像操作系统的path 只不过这个classpat ...

  5. Mybatis之Configuration初始化(配置文件.xml的解析)

    源码解读第一步我觉着应该从Mybatis如何解析配置文件开始. 1.先不看跟Spring集成如何解析,先看从SqlSessionFactoryBuilder如果解析的. String resouce ...

  6. 手机端获取用户详细地理位置(高德地图API)

    项目开发需要获取用户详细的地理位置信息,使用了高德地图API接口 1,注册高德地图开发者账号获取开发者Key 2,页面调用 <script type="text/javascript& ...

  7. 一条java开发工程师的升级路线,从初级到无语言障碍

    看了一篇文章,讲述的是如何进行后端开发升级,现在分享下,我的总结,感谢写文章的作者大大,觉得他很会坚持,虽然一直在骂人,但是,我觉得人最大的敌人就是懒惰,所以骂得好 现在写下我的总结,希望对有志者有帮 ...

  8. 看图说说JVM老年代垃圾收集器

    注:G1垃圾收集器是目前最前沿的GC收集器,未来将取代CMS垃圾收集器,可以作为整个Heap的收集器使用,不限于老年代!!!

  9. (字符串 KMP)Blue Jeans -- POJ -- 3080:

    链接: http://poj.org/problem?id=3080 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=88230#probl ...

  10. Oracle FND API–Create User

    --API - fnd_user_pkg.createuser----Example -- -- ---------------------------------------- API to CRE ...