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

摘要:
intport)throwsException{25EventLoopGroupbossGroup=newNioEventLoopGroup();分隔符));port)).sync();51}最后{52bossGroup.shutdownTracefully();

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!

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

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

原文地址:https://www.cnblogs.com/huzi007/p/5547896.html

免责声明:文章转载自《netty 解决TCP粘包与拆包问题(二)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇binary hacks读数笔记(objdump命令)Direct3D11学习:(一)开发环境配置下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

netty搭建http服务器

public class HttpServerStart { public static volatile boolean flag = false ; public static void start() { int port = 8099; EventLoopGroup bossGroup = new N...

开发者分享 | 从零开始开发一个即时通讯项目

关于聊天室项目 聊天室项目,也被称为即时通讯(IM)。 其原理是服务器是一直在启动状态的线程,不断的从客户端(App)获取消息,收到消息后,进行类型和发送目标判断,以发送到群组或者单聊的方式,客户端收到消息后进行界面的展示。 如果要自己开发即时通讯类的 App,那么必须得要后台,但是现在很多第三方工具已经给我们集成好了所有需要调用的接口工具。 比如极光 I...

RabbitMQ技术详解(转)

RabbitMQ是什么 定义 RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。 AMPQ AMQP,即Adva...

RabbitMQ面试题

1、为什么要引入MQ系统,直接读写数据库不行吗?其实就是问问你消息队列都有哪些使用场景,然后你项目里具体是什么场景,说说你在这个场景里用消息队列是什么? 面试官问你这个问题,期望的一个回答是说,你们公司有个什么业务场景,这个业务场景有个什么技术挑战,如果不用 MQ 可能会很麻烦,但是你现在用了 MQ 之后带给了你很多的好处。 先说一下消息队列常见的使用场景...

RabbitMQ双活实践(转)

有货RabbitMQ双活实践   消息服务中间件在日常工作中用途很多,如业务之间的解耦,其中 RabbitMQ 是比较容易上手且企业使用比较广泛的一种,本文主要介绍有货在使用 RabbitMQ 的一些实践与尝试。 有货的 RabbitMQ 部署架构采用双中心模式,在两套数据中心中各部署一套 RabbitMQ 集群,各中心的 RabbitMQ 服务除了需要...

搭建websocket消息推送服务,必须要考虑的几个问题

近年,不论是正在快速增长的直播,远程教育以及IM聊天场景,还是在常规企业级系统中用到的系统提醒,对websocket的需求越来越大,对websocket的要求也越来越高。从早期对websocket的应用仅限于少部分功能和IM等特殊场景,逐步发展为追求支持高并发,百万、千万级每秒通讯的高可用websocket服务。   面对各种新场景对websocket功能...