2.Netty的粘包、拆包(一)
Netty粘包、拆包
1.什么是拆包、粘包
(1)拆包、粘包介绍
TCP是个“流”协议,所谓流,就是没有界限的一串数据。大家可以想想河里的流水,是连成一片的,其间并没有分界线。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题。
(2)图解
(3)代码模拟
服务端Server
package com.xm.netty.demo02; import java.net.InetSocketAddress; import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
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.nio.NioServerSocketChannel; public class Server { private final int port; public Server(int port) {
this.port = port;
} public static void main(String[] args) { int port = 8989;
try {
new Server(port).start();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } private void start() throws InterruptedException {
EventLoopGroup g1 = new NioEventLoopGroup();
EventLoopGroup g2 = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap
.group(g1,g2)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress( port))
.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new ServerHandler());
}
});
ChannelFuture future = bootstrap.bind().sync();
future.channel().closeFuture().sync();
} finally {
g1.shutdownGracefully().sync();
g2.shutdownGracefully().sync();
}
} }服务端ServerHandler
package com.xm.netty.demo02; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.CharsetUtil; public class ServerHandler extends ChannelHandlerAdapter { @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf in = (ByteBuf) msg;
String str = in.toString(CharsetUtil.UTF_8);
System.out.println("Server:"+str);
str = "服务器返回--->"+ str;
ctx.writeAndFlush(Unpooled.copiedBuffer(str.getBytes()));
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
} @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now())+"一个客户端连接!");
} }客户端Client
package com.xm.netty.demo02; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import io.netty.bootstrap.Bootstrap;
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; public class Client { private final int port;
private final String host; public Client(int port, String host) {
this.port = port;
this.host = host;
} public static void main(String[] args) {
String host = "127.0.0.1";
int port = 8989;
try {
new Client(port, host).start();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} private void start() throws InterruptedException { EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap
.group(group)
.channel(NioSocketChannel.class)
.remoteAddress(host, port)
.handler(new ChannelInitializer<SocketChannel>() { @Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new ClientHandler());
} }); ChannelFuture future = bootstrap.connect().sync(); for(int i=10;i<20;i++) {
String str = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now()) + "---- " +i+"<<<";
future.channel().writeAndFlush(Unpooled.copiedBuffer(str.getBytes()));
} future.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
} } }客户端ClientHandler
package com.xm.netty.demo02; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil; public class ClientHandler extends ChannelHandlerAdapter { @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { try { ByteBuf in = (ByteBuf) msg;
String str = in.toString(CharsetUtil.UTF_8);
System.out.println("Client:"+str); } finally {
ReferenceCountUtil.release(msg);
}
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
} @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now())+" 已连接上服务器!");
} }添加依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xm</groupId>
<artifactId>netty</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>5.0.0.Alpha2</version>
</dependency>
</dependencies>
</project>
预期结果
1)服务器
2018-10-11T18:37:19.857一个客户端连接!
Server:2018-10-11T18:37:19.855---- 10<<<
Server:2018-10-11T18:37:20.377---- 11<<<
Server:2018-10-11T18:37:20.877---- 12<<<
Server:2018-10-11T18:37:21.378---- 13<<<
Server:2018-10-11T18:37:21.879---- 14<<<
Server:2018-10-11T18:37:22.379---- 15<<<
Server:2018-10-11T18:37:22.879---- 16<<<
Server:2018-10-11T18:37:23.38---- 17<<<
Server:2018-10-11T18:37:23.881---- 18<<<
Server:2018-10-11T18:37:24.382---- 19<<<
(2)客户端
2018-10-11T18:37:19.855 已连接上服务器!
Client:服务器返回--->2018-10-11T18:37:19.855---- 10<<<
Client:服务器返回--->2018-10-11T18:37:20.377---- 11<<<
Client:服务器返回--->2018-10-11T18:37:20.877---- 12<<<
Client:服务器返回--->2018-10-11T18:37:21.378---- 13<<<
Client:服务器返回--->2018-10-11T18:37:21.879---- 14<<<
Client:服务器返回--->2018-10-11T18:37:22.379---- 15<<<
Client:服务器返回--->2018-10-11T18:37:22.879---- 16<<<
Client:服务器返回--->2018-10-11T18:37:23.38---- 17<<<
Client:服务器返回--->2018-10-11T18:37:23.881---- 18<<<
Client:服务器返回--->2018-10-11T18:37:24.382---- 19<<<
实际结果
(1)服务器
2018-10-11T18:35:40.988一个客户端连接!
Server:2018-10-11T18:35:40.986---- 10<<<2018-10-11T18:35:41.01---- 11<<<2018-10-11T18:35:41.01---- 12<<<2018-10-11T18:35:41.01---- 13<<<2018-10-11T18:35:41.01---- 14<<<2018-10-11T18:35:41.01---- 15<<<2018-10-11T18:35:41.01---- 16<<<2018-10-11T18:35:41.01---- 17<<<2018-10-11T18:35:41.01---- 18<<<2018-10-11T18:35:41.01---- 19<<<(2)客户端
2018-10-11T18:35:40.986 已连接上服务器!
Client:服务器返回--->2018-10-11T18:35:40.986---- 10<<<2018-10-11T18:35:41.01---- 11<<<2018-10-11T18:35:41.01---- 12<<<2018-10-11T18:35:41.01---- 13<<<2018-10-11T18:35:41.01---- 14<<<2018-10-11T18:35:41.01---- 15<<<2018-10-11T18:35:41.01---- 16<<<2018-10-11T18:35:41.01---- 17<<<2018-10-11T18:35:41.01---- 18<<<2018-10-11T18:35:41.01---- 19<<<
最新文章
- Bootstrap相关资料
- 支持Java Spring MVC
- JAVASCRIPT实现简单计算器
- MSsql bcp
- HTML元素的ID和Name属性的区别
- HTML初学者常用标签及属性
- MatlabR2015b用了一段时间之后需要重新激活
- BZOJ 1926: [Sdoi2010]粟粟的书架(主席树,二分答案)
- 利用Node的chokidar 监听文件改变的文件。
- Linux 系统化学习系列文章总目录(持续更新中)
- PeopleSoft 单点登录
- 为什么zookeeper集群中节点配置个数是奇数个?
- 2012年NOIP普及组 摆花
- 【Tensorflow】tensorboard
- CentOS 7卸载Docker
- Navicat 12破解工具 +安装包
- java基础27 单例集合Collection及其常用方法
- python邮件
- Mysql 表锁定的问题
- 第2天:JavaScript基础(运算符、案例、循环、冒泡以及prompt提示输入框)