netty权威指南--------第四章TCP粘包/拆包问题

第三章中的示例用于功能测试一般没有问题,但当压力上来或者发送大报文时,就会存在粘包/拆包问题。

这时就需要使用LineBasedFrameDecoder+StringDecoder

client端请求改为连续的100次

package com.xiaobing.netty.fourth;

import java.net.SocketAddress;

import org.omg.CORBA.Request;

import io.netty.buffer.ByteBuf;

import io.netty.buffer.Unpooled;

import io.netty.channel.ChannelHandler;

import io.netty.channel.ChannelHandlerAdapter;

import io.netty.channel.ChannelHandlerContext;

import io.netty.channel.ChannelPromise;

public class TimeClientHandler extends ChannelHandlerAdapter {

//private static final Logger  LOGGER= new Logger.getLogger(TimeClientHandler.class);

private int counter;

private byte[] req;

public TimeClientHandler() {

req = ("QUERY TIME ORDER" +System.getProperty("line.separator") ).getBytes();

}

/*

* 客户端和服务端TCP链路建立成功后被调用

* @see io.netty.channel.ChannelHandlerAdapter#channelActive(io.netty.channel.ChannelHandlerContext)

*/

@Override

public void channelActive(ChannelHandlerContext ctx) throws Exception {

//将请求消息发送至服务端

ByteBuf messageBuf = null;

//以下情况会发生tcp粘包

for(int i=0; i<100; i++){

messageBuf = Unpooled.buffer(req.length);

messageBuf.writeBytes(req);

ctx.writeAndFlush(messageBuf);

}

}

/*

* 服务端返回应答消息时被调用

* @see io.netty.channel.ChannelHandlerAdapter#channelRead(io.netty.channel.ChannelHandlerContext, java.lang.Object)

*/

@Override

public void channelRead(ChannelHandlerContext ctx, Object msg)

throws Exception {

// ByteBuf buf = (ByteBuf) msg;

// byte[] req = new byte[buf.readableBytes()];

// buf.readBytes(req);

// String bodyString = new String(req,"UTF-8");

String bodyString = (String)msg;

System.out.println("Now is :" + bodyString + "; the count is :" + ++counter);

}

@Override

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)

throws Exception {

ctx.close();

}

}

package com.xiaobing.netty.fourth;

import java.security.acl.Group;

import io.netty.bootstrap.Bootstrap;

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.LineBasedFrameDecoder;

import io.netty.handler.codec.string.StringDecoder;

public class TimeClient {

public void connect(int port , String host) throws Exception{

EventLoopGroup group = new NioEventLoopGroup();

try{

//客户端启动辅助类

Bootstrap b = new Bootstrap();

b.group(group).channel(NioSocketChannel.class)

.option(ChannelOption.TCP_NODELAY, true)

.handler(new ChannelInitializer<SocketChannel>() {

//在初始化时将channelHandler 设置到channelpipeline中

@Override

protected void initChannel(SocketChannel ch) throws Exception {

ch.pipeline().addLast(new LineBasedFrameDecoder(1024));

ch.pipeline().addLast(new StringDecoder());

ch.pipeline().addLast(new TimeClientHandler());

}

});

//发起异步连接

ChannelFuture f = b.connect(host,port).sync();

//等待客户端链路关闭

f.channel().closeFuture().sync();

}finally{

group.shutdownGracefully();

}

}

public static void main(String[] args) throws Exception {

int port = 8080;

new TimeClient().connect(port, "127.0.0.1");

}

}

server端

package com.xiaobing.netty.fourth;

import io.netty.bootstrap.ServerBootstrap;

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.LineBasedFrameDecoder;

import io.netty.handler.codec.string.StringDecoder;

public class TimeServer {

public void bind(int port) throws Exception{

System.out.println("-------TimeServer start----------");

//服务端接受客户端的连接线程

EventLoopGroup bossGroup = new NioEventLoopGroup();

//网络读写线程

EventLoopGroup workerGroup = new NioEventLoopGroup();

//服务端辅助启动类

ServerBootstrap b = new ServerBootstrap();

try {

b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)

.option(ChannelOption.SO_BACKLOG, 1024)

.childHandler(new ChildChannelHandler());

//阻塞等待端口绑定完成

System.out.println("-------TimeServer wait----------");

ChannelFuture f = b.bind(port).sync();

//等待服务端链路关闭

f.channel().closeFuture().sync();

}finally{

bossGroup.shutdownGracefully();

workerGroup.shutdownGracefully();

}

}

//网络IO处理类

private class ChildChannelHandler extends ChannelInitializer<SocketChannel>{

@Override

protected void initChannel(SocketChannel arg0) throws Exception {

//发生tcp粘包的情况

// arg0.pipeline().addLast(new TimeServerHandler());

System.out.println("-------ChildChannelHandler----------");

arg0.pipeline().addLast(new LineBasedFrameDecoder(1024));

arg0.pipeline().addLast(new StringDecoder());

arg0.pipeline().addLast(new TimeServerHandler());

}

}

public static void main(String[] args) throws Exception {

int port = 8080;

new TimeServer().bind(port);

}

}

package com.xiaobing.netty.fourth;

import io.netty.buffer.ByteBuf;

import io.netty.buffer.Unpooled;

import io.netty.channel.ChannelHandlerAdapter;

import io.netty.channel.ChannelHandlerContext;

//对网络事件进行读写

public class TimeServerHandler extends ChannelHandlerAdapter {

private int counter;

@Override

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception{

// ByteBuf buf = (ByteBuf) msg;

// //获取缓冲区可读字节数

// byte[] req =  new byte[buf.readableBytes()];

//

// buf.readBytes(req);

// String body = new String(req,"UTF-8").substring(0,req.length - System.getProperty("line.separator").length());

String  body = (String)msg;

System.out.println("The time server receive order:" + body + "; the count is :" + ++counter);

String currentTimeString  = "QUERY TIME ORDER".equalsIgnoreCase(body)?new java.util.Date(System.currentTimeMillis()).toString() :"BAD ORDER";

currentTimeString = currentTimeString + System.getProperty("line.separator");

//应答消息

ByteBuf resp = Unpooled.copiedBuffer(currentTimeString.getBytes());

ctx.writeAndFlush(resp);

}

@Override

public void channelReadComplete(ChannelHandlerContext ctx){

//将消息发送队列的消息写入socketchannel中

ctx.flush();

}

@Override

public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause){

//发生异常时,关闭ctx

ctx.close();

}

}

时间: 2024-08-06 11:36:15

netty权威指南--------第四章TCP粘包/拆包问题的相关文章

Netty中使用MessagePack时的TCP粘包问题与解决方案

[toc] Netty中使用MessagePack时的TCP粘包问题与解决方案 通过下面的实例代码来演示在Netty中使用MessagPack时会出现的TCP粘包问题,为了学习的连贯性,参考了<Netty权威指南>第7章中的代码,但是需要注意的是,书中并没有提供完整代码,提供的代码都是片段性的,所以我根据自己的理解把服务端的代码和客户端的代码写了出来,可以作为参考. 仍然需要注意的是,我使用的是Netty 4.x的版本. 另外我在程序代码中写了非常详细的注释,所以这里不再进行更多的说明. 在使

【游戏开发】Netty TCP粘包/拆包问题的解决办法(二)

上一篇:[Netty4.X]Unity客户端与Netty服务器的网络通信(一) 一.什么是TCP粘包/拆包 如图所示,假如客户端分别发送两个数据包D1和D2给服务端,由于服务端一次读取到的字节数是不确定的,故可能存在以下4中情况: 第一种情况:Server端分别读取到D1和D2,没有产生粘包和拆包的情况. 第二种情况:Server端一次接收到两个数据包,D1和D2粘合在一起,被称为TCP粘包. 第三种情况:Server端分2次读取到2个数据包,第一次读取到D1包和D2包的部分内容D2_1,第二次

Netty(三)TCP粘包拆包处理

tcp是一个“流”的协议,一个完整的包可能会被TCP拆分成多个包进行发送,也可能把小的封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题. 粘包.拆包问题说明 假设客户端分别发送数据包D1和D2给服务端,由于服务端一次性读取到的字节数是不确定的,所以可能存在以下4种情况. 1.服务端分2次读取到了两个独立的包,分别是D1,D2,没有粘包和拆包: 2.服务端一次性接收了两个包,D1和D2粘在一起了,被成为TCP粘包; 3.服务端分2次读取到了两个数据包,第一次读取到了完整的D1和D2包的部

Netty学习之TCP粘包/拆包

一.TCP粘包/拆包问题说明,如图 二.未考虑TCP粘包导致功能异常案例 按照设计初衷,服务端应该收到100条查询时间指令的请求查询,客户端应该打印100次服务端的系统时间 1.服务端类 package com.phei.netty.s2016042302; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitial

netty解决tcp粘包拆包问题

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

TCP粘包/拆包问题

无论是服务端还是客户端,当我们读取或者发送消息的时候,都需要考虑TCP底层的粘包/拆包机制. TCP粘包/拆包 TCP是个"流"协议,所谓流,就是没有界限的一串数据.大家可以想想河里的流水,是连成一片的,其间并没有分界线.TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题. TCP粘包/拆包问题说明 假设客户

TCP 粘包/拆包问题

简介 TCP 是一个’流’协议,所谓流,就是没有界限的一串数据. 大家可以想想河里的流水,是连成一片的.期间并没有分界线, TCP 底层并不了解上层业务数据的具体含义 ,它会根据 TCP 缓冲区的实际情况进行包得划分,所以在业务上认为,一个完整的包可能会被 TCP 拆分成多个包进行发送 . 也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的 TCP 拆包和粘包. TCP 粘包/拆包问题说明 我们可以通过图解对 TCP 粘包和拆包进行说明.粘包问题示例图: 假设客户端分别发送了两个数据包

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

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

(入门篇 NettyNIO开发指南)第四章-TIP黏包/拆包问题解决之道

熟悉TCP编程的读者可能都知道,无论是服务端还是客户端,当我们读取或者发送消息的时候,都需要考虑TCP底层的粘包/拆包机制.木章开始我们先简单介绍TCP粘包/拆包的基础知识,然后模拟一个没有考虑TCP粘包/拆包导致功能异常的案例,最后通过正确例米探讨Netty是如何解决这个问题的.如果你已经熟悉了TCP粘包和拆包的相知识,建议你直接跳到代码讲解小节,看Netty是如何解决这个问题的.本章主要内容包: TCP粘包/拆包的基础知识 没考虑TCP粘包/拆包的问题案例 使用Netty解决读半包问题 4.