netty 解决TCP粘包与拆包问题(二)

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

1.消息固定长度

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

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

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

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

服务端

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

客服端:

 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
14
15     @Override
16     public void channelActive(ChannelHandlerContext ctx) throws Exception {
17         //发送消息,模拟发送向服务端发送1000条数据
18         for(int i=0,j=1000;i<j;i++){
19             ctx.writeAndFlush(Unpooled.copiedBuffer(REQUEST_TEST_DATA.getBytes()));
20         }
21     }
22
23     @Override
24     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
25         String sendMsg=(String)msg;
26         System.out.println("客户端发送给服务器的次数:"+(++count)+",服务器接收数据为:"+sendMsg);
27     }
28
29
30
31     @Override
32     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
33         ctx.flush();
34     }
35
36     @Override
37     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
38         cause.printStackTrace();
39         ctx.close();
40     }
41
42
43 }

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

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

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

时间: 2024-10-01 05:32:02

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

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

今天使用netty的固定长度进行解码 固定长度解码的原理就是按照指定消息的长度对消息自动解码. 在netty实现中,只需要采用FiexedLengthFrameDecoder解码器即可... 以下是服务端代码 1 package com.ming.netty.nio.stickpack; 2 3 4 5 import java.net.InetSocketAddress; 6 7 import io.netty.bootstrap.ServerBootstrap; 8 import io.net

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

服务端 package org.zln.netty.five.timer; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; impo

netty解决tcp粘包拆包问题

tcp粘包拆包解决方案 1.发送定长的消息 server端:                    EventLoopGroup pGroup = new NioEventLoopGroup(); EventLoopGroup cGroup = new NioEventLoopGroup(); ServerBootstrap b = new ServerBootstrap(); b.group(pGroup, cGroup)  .channel(NioServerSocketChannel.cl

Netty的TCP粘包/拆包(源码二)

假设客户端分别发送了两个数据包D1和D2给服务器,由于服务器端一次读取到的字节数是不确定的,所以可能发生四种情况: 1.服务端分两次读取到了两个独立的数据包,分别是D1和D2,没有粘包和拆包. 2.服务端一次接收到了两个数据包,D1和D2粘合在一起,被称为TCP粘包. 3.服务端分两次读取到了两个数据包,第一次读取到了完整的D1包和D2包的部分内容,第二次读取到了D2包的剩余内容,这被称为TCP拆包. 4.服务端分两次读取到了两个数据包,第一次读取到了D1包的部分内容D1_1,第二次读取到了D1

Netty中LineBasedFrameDecoder解码器使用与分析:解决TCP粘包问题

[toc] Netty中LineBasedFrameDecoder解码器使用与分析:解决TCP粘包问题 上一篇文章<Netty中TCP粘包问题代码示例与分析>演示了使用了时间服务器的例子演示了TCP的粘包问题,这里使用LineBasedFrameDecoder就是用来解决这个问题的. 不过需要注意的是,LineBasedFrameDecoder见名知其义,可见其是与行相关的,而在前面演示TCP粘包问题时,作者是有意在发送的消息中都加入了换行符,目的也是为了在后面去讲解LineBasedFram

TCP粘包,拆包及解决方法

粘包拆包问题是处于网络比较底层的问题,在数据链路层.网络层以及传输层都有可能发生.我们日常的网络应用开发大都在传输层进行,由于UDP有消息保护边界,不会发生粘包拆包问题,因此粘包拆包问题只发生在TCP协议中. 什么是粘包.拆包? 假设客户端向服务端连续发送了两个数据包,用packet1和packet2来表示,那么服务端收到的数据可以分为三种,现列举如下: 第一种情况,接收端正常收到两个数据包,即没有发生拆包和粘包的现象,此种情况不在本文的讨论范围内. 第二种情况,接收端只收到一个数据包,由于TC

关于TCP粘包和拆包的终极解答

关于TCP粘包和拆包的终极解答 程序员行业有一些奇怪的错误的观点(误解),这些误解非常之流行,而且持有这些错误观点的人经常言之凿凿,打死也不相信自己有错,实在让人啼笑皆非.究其原因,还是因为这些错误观点所对应的正确观点不符合人的正常思维习惯,是扭曲人的直观感受的. 有两个错误观点非常之经典,一而再,再而三的出现,就跟韭菜一样,割不完,还越长越多.一是经典的"服务器最多65536个连接"误解,打开链接看介绍.另一个就是这里要讲的TCP"粘包"和"拆包&quo

TCP粘包和拆包

TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务.收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包.这样,接收端,就难于分辨出来了,必须提供科学的拆包机制.即面向流的通信是无消息保护边界的.        图解TCP的粘包和拆包 假设客户端分别发送了两个数据包D1和

TCP粘包的拆包处理

因为TCP是流式处理的,所以包没有边界,必须设计一个包头,里面表示包的长度(一般用字节表示),根据这个来逐个拆包.如果对于发送/接收频率不高的话,一般也就不做拆包处理了,因为不大可能有粘包现象. 以下是粘包和拆包的分析: http://blog.csdn.net/zhangxinrun/article/details/6721495 用Qt的TCPSocket读出的数据来拆: http://www.aiuxian.com/article/p-1732805.html 我是根据以上链接例子Qt的逻