TCP以流的方式进行数据传输,上层应用协议为了对消息的区分,采用了以下几种方法。

1.消息固定长度

2.第一篇讲的回车换行符形式

3.以特殊字符作为消息结束符的形式

4.通过消息头中定义长度字段来标识消息的总长度

一、采用指定分割符解决粘包与拆包问题

服务端

  1. package com.ming.netty.nio.stickpack;
  2.  
  3. import java.net.InetSocketAddress;
  4.  
  5. import io.netty.bootstrap.ServerBootstrap;
  6. import io.netty.buffer.ByteBuf;
  7. import io.netty.buffer.Unpooled;
  8. import io.netty.channel.ChannelFuture;
  9. import io.netty.channel.ChannelInitializer;
  10. import io.netty.channel.ChannelOption;
  11. import io.netty.channel.EventLoopGroup;
  12. import io.netty.channel.nio.NioEventLoopGroup;
  13. import io.netty.channel.socket.SocketChannel;
  14. import io.netty.channel.socket.nio.NioServerSocketChannel;
  15. import io.netty.handler.codec.DelimiterBasedFrameDecoder;
  16. import io.netty.handler.codec.string.StringDecoder;
  17. import io.netty.handler.logging.LogLevel;
  18. import io.netty.handler.logging.LoggingHandler;
  19.  
  20. public class EchoServer {
  21.  
  22. public void bind(String addr,int port) throws Exception{
  23. EventLoopGroup bossGroup=new NioEventLoopGroup();
  24. EventLoopGroup workGroup=new NioEventLoopGroup();
  25. try {
  26. ServerBootstrap server=new ServerBootstrap();
  27. server.group(bossGroup,workGroup)
  28. .channel(NioServerSocketChannel.class)
  29. .option(ChannelOption.SO_BACKLOG, 100)
  30. .handler(new LoggingHandler(LogLevel.INFO))
  31. .childHandler(new ChannelInitializer<SocketChannel>() {
  32.  
  33. @Override
  34. protected void initChannel(SocketChannel sc) throws Exception {
  35. ByteBuf delimiter=Unpooled.copiedBuffer("$_".getBytes());//指定消息分割符处理数据
  36. sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));//如果取消了分割符解码,就会出现TCP粘包之类的问题了
  37. sc.pipeline().addLast(new StringDecoder());
  38. sc.pipeline().addLast(new EchoServerHandler());
  39.  
  40. }
  41.  
  42. });
  43. ChannelFuture f=server.bind(new InetSocketAddress(addr, port)).sync();
  44. System.out.println("启动服务器:"+f.channel().localAddress());
  45. //等等服务器端监听端口关闭
  46. f.channel().closeFuture().sync();
  47. } catch (Exception e) {
  48. e.printStackTrace();
  49. }finally{
  50. bossGroup.shutdownGracefully();
  51. workGroup.shutdownGracefully();
  52. }
  53. }
  54.  
  55. public static void main(String[] args) throws Exception{
  56. new EchoServer().bind("192.168.1.108", 8500);
  57. }
  58.  
  59. }
  1. package com.ming.netty.nio.stickpack;
  2.  
  3. import io.netty.buffer.ByteBuf;
  4. import io.netty.buffer.Unpooled;
  5. import io.netty.channel.ChannelHandlerAdapter;
  6. import io.netty.channel.ChannelHandlerContext;
  7.  
  8. public class EchoServerHandler extends ChannelHandlerAdapter{
  9.  
  10. int count=0;
  11.  
  12. @Override
  13. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  14.  
  15. String body=(String)msg;
  16. System.out.println("服务器收到"+(++count)+"次客户端消息,消息是:"+body);
  17. body+="$_";
  18. ByteBuf rep=Unpooled.copiedBuffer(body.getBytes());
  19. ctx.writeAndFlush(rep);
  20. }
  21.  
  22. @Override
  23. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  24. cause.printStackTrace();
  25. ctx.close();
  26. }
  27.  
  28. }

客服端:

  1. package com.ming.netty.nio.stickpack;
  2.  
  3. import java.net.InetSocketAddress;
  4.  
  5. import io.netty.bootstrap.Bootstrap;
  6. import io.netty.buffer.ByteBuf;
  7. import io.netty.buffer.Unpooled;
  8. import io.netty.channel.ChannelFuture;
  9. import io.netty.channel.ChannelInitializer;
  10. import io.netty.channel.ChannelOption;
  11. import io.netty.channel.EventLoopGroup;
  12. import io.netty.channel.nio.NioEventLoopGroup;
  13. import io.netty.channel.socket.SocketChannel;
  14. import io.netty.channel.socket.nio.NioSocketChannel;
  15. import io.netty.handler.codec.DelimiterBasedFrameDecoder;
  16. import io.netty.handler.codec.string.StringDecoder;
  17.  
  18. public class EchoClient {
  19.  
  20. public void connect(String addr,int port) throws Exception{
  21. EventLoopGroup workGroup=new NioEventLoopGroup();
  22. try {
  23. Bootstrap b=new Bootstrap();
  24. b.group(workGroup)
  25. .channel(NioSocketChannel.class)
  26. .option(ChannelOption.TCP_NODELAY, true)
  27. .handler(new ChannelInitializer<SocketChannel>() {
  28.  
  29. @Override
  30. protected void initChannel(SocketChannel sc) throws Exception {
  31. ByteBuf delimiter=Unpooled.copiedBuffer("$_".getBytes());//指定消息分割符
  32. sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));
  33. sc.pipeline().addLast(new StringDecoder());
  34. sc.pipeline().addLast(new EchoClientHandler());
  35. }
  36.  
  37. });
  38.  
  39. ChannelFuture f=b.connect(new InetSocketAddress(addr, port)).sync();
  40. System.out.println("连接服务器:"+f.channel().remoteAddress()+",本地地址:"+f.channel().localAddress());
  41. f.channel().closeFuture().sync();//等待客户端关闭连接
  42.  
  43. } catch (Exception e) {
  44. e.printStackTrace();
  45. }finally{
  46. workGroup.shutdownGracefully();
  47. }
  48. }
  49.  
  50. public static void main(String[] args) throws Exception{
  51. new EchoClient().connect("192.168.1.108", 8500);
  52. }
  53. }
  1. package com.ming.netty.nio.stickpack;
  2.  
  3. import io.netty.buffer.Unpooled;
  4. import io.netty.channel.ChannelHandlerAdapter;
  5. import io.netty.channel.ChannelHandlerContext;
  6.  
  7. public class EchoClientHandler extends ChannelHandlerAdapter{
  8.  
  9. int count=0;
  10.  
  11. static final String REQUEST_TEST_DATA="I love you....$_";
  12.  
  13. @Override
  14. public void channelActive(ChannelHandlerContext ctx) throws Exception {
  15. //发送消息,模拟发送向服务端发送1000条数据
  16. for(int i=0,j=1000;i<j;i++){
  17. ctx.writeAndFlush(Unpooled.copiedBuffer(REQUEST_TEST_DATA.getBytes()));
  18. }
  19. }
  20.  
  21. @Override
  22. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  23. String sendMsg=(String)msg;
  24. System.out.println("客户端发送给服务器的次数:"+(++count)+",服务器接收数据为:"+sendMsg);
  25. }
  26.  
  27. @Override
  28. public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
  29. ctx.flush();
  30. }
  31.  
  32. @Override
  33. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  34. cause.printStackTrace();
  35. ctx.close();
  36. }
  37.  
  38. }

很多事情看代码解决,hello world!

下篇打算写定长解码了...最后写一下通过消息头中定义长度字段来标识消息的总长度来解码玩玩....

感觉可以点个赞吧,好自恋一把

netty 解决TCP粘包与拆包问题(二)的更多相关文章

  1. netty 解决TCP粘包与拆包问题(一)

    1.什么是TCP粘包与拆包 首先TCP是一个"流"协议,犹如河中水一样连成一片,没有严格的分界线.当我们在发送数据的时候就会出现多发送与少发送问题,也就是TCP粘包与拆包.得不到我 ...

  2. netty 解决TCP粘包与拆包问题(三)

    今天使用netty的固定长度进行解码 固定长度解码的原理就是按照指定消息的长度对消息自动解码. 在netty实现中,只需要采用FiexedLengthFrameDecoder解码器即可... 以下是服 ...

  3. 【Netty】TCP粘包和拆包

    一.前言 前面已经基本上讲解完了Netty的主要内容,现在来学习Netty中的一些可能存在的问题,如TCP粘包和拆包. 二.粘包和拆包 对于TCP协议而言,当底层发送消息和接受消息时,都需要考虑TCP ...

  4. Netty解决TCP粘包/拆包问题 - 按行分隔字符串解码器

    服务端 package org.zln.netty.five.timer; import io.netty.bootstrap.ServerBootstrap; import io.netty.cha ...

  5. 1. Netty解决Tcp粘包拆包

    一. TCP粘包问题 实际发送的消息, 可能会被TCP拆分成很多数据包发送, 也可能把很多消息组合成一个数据包发送 粘包拆包发生的原因 (1) 应用程序一次写的字节大小超过socket发送缓冲区大小 ...

  6. 【Netty】使用解码器Decoder解决TCP粘包和拆包问题

    解码器Decoder和ChannelHandler的关系 netty的解码器通常是继承自ByteToMessageDecoder,而它又是继承自ChannelInboundHandlerAdapter ...

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

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

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

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

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

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

随机推荐

  1. 第一章-第一题(小学生四则运算)--By郭青云

    1.项目需求 a) 除了整数以外,还要支持真分数的四则运算. (例如:  1/6 + 1/8 = 7/24) b) 让程序能接受用户输入答案,并判定对错. 最后给出总共 对/错 的数量. c) 逐步扩 ...

  2. Spring-Aop入门

    (一)Aop术语定义 1.通知(advice) 通知定义了切面要做什么工作,即调用的方法,同时定义了什么时候做这些工作,即以下五种类型 (1)前置通知(Before) :在目标方法调用之前执行切面方法 ...

  3. 动态调用webservice(部分转载)

    动态调用webservice,做个笔记: public class WSHelper { /// < summary> /// 动态调用web服务 /// < /summary> ...

  4. git常使用命令整理

    1.git撤销本地所有修改(tracked和untracked) . git clean -df . git reset --hard 第一个命令只删除所有untracked的文件,如果文件已经被tr ...

  5. 短期连载 第1回 万代南梦宫工作室动画的流派 BNS动作捕捉汐留工作室的采访

    原文链接:http://cgworld.jp/interview/201607-bandainamco.html     因开发了[偶像大师],[铁拳],[XX传说]系列等各种游戏而被广为人知的万代南 ...

  6. 带你玩转JavaWeb开发之五-如何完成响应式开发页面

    响应式页面开发 使用BootStrap开发一个响应式的页面出来 响应式开发就是同一个页面在PC端与手机端Pad端显示不同的效果,以给用户更好的体验 需求分析 开发一套页面,让用户能够在PC端, Pad ...

  7. Thinkphp控制器,1.多层控制器2.多级控制器

    1.多层控制器 ThinkPHP的控制器支持多层和多级,多层指的是控制器可以分层,例如除了默认的Controller控制器层(我们可以称之为访问控制器),还可以添加事件控制器(层),例如: ├─Con ...

  8. jQuery $ 第二个参数的用法

    jQuery(selector, [context]),相当于 $(context).find(selector) 或者 context.find(selector) $('div').each(fu ...

  9. 上传图片插件鼠标手cursor:pointer;不生效

    问题: 只在谷歌里失效; 解决: font-size:0; 参考: http://jingyan.baidu.com/article/48b558e32fabb67f38c09a81.html htt ...

  10. 2.Linux如何学习

    Linux的应用: 企业应用 个人应用 平行运算:所谓的平行运算指的是将原本的工作分成多份然后交给多台主机去运算,最终再将结果收集起来的一种方式.由于通过高速网络使用到多台主机(集群),将原本需要很长 ...