netty 解决TCP粘包与拆包问题(二)
2016-05-31 22:45
519 查看
TCP以流的方式进行数据传输,上层应用协议为了对消息的区分,采用了以下几种方法。
1.消息固定长度
2.第一篇讲的回车换行符形式
3.以特殊字符作为消息结束符的形式
4.通过消息头中定义长度字段来标识消息的总长度
一、采用指定分割符解决粘包与拆包问题
服务端
客服端:
很多事情看代码解决,hello world!
下篇打算写定长解码了...最后写一下通过消息头中定义长度字段来标识消息的总长度来解码玩玩....
感觉可以点个赞吧,好自恋一把
1.消息固定长度
2.第一篇讲的回车换行符形式
3.以特殊字符作为消息结束符的形式
4.通过消息头中定义长度字段来标识消息的总长度
一、采用指定分割符解决粘包与拆包问题
服务端
package com.ming.netty.nio.stickpack; import java.net.InetSocketAddress; 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.string.StringDecoder; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; public class EchoServer { public void bind(String addr,int port) throws Exception{ EventLoopGroup bossGroup=new NioEventLoopGroup(); EventLoopGroup workGroup=new NioEventLoopGroup(); try { ServerBootstrap server=new ServerBootstrap(); server.group(bossGroup,workGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 100) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel sc) throws Exception { ByteBuf delimiter=Unpooled.copiedBuffer("$_".getBytes());//指定消息分割符处理数据 sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));//如果取消了分割符解码,就会出现TCP粘包之类的问题了 sc.pipeline().addLast(new StringDecoder()); sc.pipeline().addLast(new EchoServerHandler()); } }); ChannelFuture f=server.bind(new InetSocketAddress(addr, port)).sync(); System.out.println("启动服务器:"+f.channel().localAddress()); //等等服务器端监听端口关闭 f.channel().closeFuture().sync(); } catch (Exception e) { e.printStackTrace(); }finally{ bossGroup.shutdownGracefully(); workGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception{ new EchoServer().bind("192.168.1.108", 8500); } }
package com.ming.netty.nio.stickpack; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerContext; public class EchoServerHandler extends ChannelHandlerAdapter{ int count=0; @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { String body=(String)msg; System.out.println("服务器收到"+(++count)+"次客户端消息,消息是:"+body); body+="$_"; ByteBuf rep=Unpooled.copiedBuffer(body.getBytes()); ctx.writeAndFlush(rep); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }
客服端:
package com.ming.netty.nio.stickpack; import java.net.InetSocketAddress; 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.ChannelOption; 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.string.StringDecoder; public class EchoClient { public void connect(String addr,int port) throws Exception{ EventLoopGroup workGroup=new NioEventLoopGroup(); try { Bootstrap b=new Bootstrap(); b.group(workGroup) .channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel sc) throws Exception { ByteBuf delimiter=Unpooled.copiedBuffer("$_".getBytes());//指定消息分割符 sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter)); sc.pipeline().addLast(new StringDecoder()); sc.pipeline().addLast(new EchoClientHandler()); } }); ChannelFuture f=b.connect(new InetSocketAddress(addr, port)).sync(); System.out.println("连接服务器:"+f.channel().remoteAddress()+",本地地址:"+f.channel().localAddress()); f.channel().closeFuture().sync();//等待客户端关闭连接 } catch (Exception e) { e.printStackTrace(); }finally{ workGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception{ new EchoClient().connect("192.168.1.108", 8500); } }
package com.ming.netty.nio.stickpack; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerContext; public class EchoClientHandler extends ChannelHandlerAdapter{ int count=0; static final String REQUEST_TEST_DATA="I love you....$_"; @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { //发送消息,模拟发送向服务端发送1000条数据 for(int i=0,j=1000;i<j;i++){ ctx.writeAndFlush(Unpooled.copiedBuffer(REQUEST_TEST_DATA.getBytes())); } } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { String sendMsg=(String)msg; System.out.println("客户端发送给服务器的次数:"+(++count)+",服务器接收数据为:"+sendMsg); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }
很多事情看代码解决,hello world!
下篇打算写定长解码了...最后写一下通过消息头中定义长度字段来标识消息的总长度来解码玩玩....
感觉可以点个赞吧,好自恋一把
相关文章推荐
- HTTP与HTTPS比较
- Go学习笔记三:网络通信
- Anddroid检测网络是否连接
- TCP和UDP的区别(热门面试题目)
- 多进程的网络服务的一般模型
- C#实现http多线程断点续传下载文件
- WCF实现全双工通信笔记
- 机器学习/CNN系列小问题(1):逻辑回归和神经网络之间有什么关系?
- java.lang.String cannot be cast to org.springframework.http.MediaType 异常分析
- 简单的网络技术及数据解析
- https -- 超文本传输安全协议
- 微信无法连接到服务器怎么诊断网络【微信高级教程3】
- Linux网络编程:一个简单的正向代理服务器的实现
- TCP慢启动、拥塞控制、快速重传、快速恢复
- java WEB学习笔记32:HttpSession 接口常用方法 及 HttpServletRequest接口中的Session方法 Demo
- 网络第一课
- xListView(上拉刷新下拉加载,xml解析)中添加网络请求
- 关于人工智能的幻想(九)人工智能与网络游戏第二部分
- 虚拟机网络类型选择
- #码神学习#第四天