There are three main solutions for tcp unpacking and sticking:
Unpacking and sticking scheme:
1. The length of the message is fixed, and the lack of space should be filled in (fill manually, it will not be filled automatically)
2. Add special characters at the end of the package for segmentation, emphasizing that it is added at the end of the package. Once the received message is disassembled in this way, it must be sent in this way, otherwise the message will not be received.
3. Divide the message into a message header and a message body, and include a field representing the length of the message in the message header, and then perform business logic processing.
package
com.aowin.netty.chaibaoAndNianbao;
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.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.string.StringDecoder; public class Client { public void connect() { EventLoopGroup workGroup = new NioEventLoopGroup(); Bootstrap bootstrap = new Bootstrap(); bootstrap.group(workGroup).channel(NioSocketChannel. class) .handler( new ChannelInitializer<SocketChannel>() { protected void initChannel(SocketChannel socketChannel) throws
Exception {
/*// Method 1: Add special characters to the end of the packet // Set the special separator ByteBuf f=Unpooled.copiedBuffer("$_".getBytes()); socketChannel.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, f) );*/ // Method 2 Fixed length key class FixedLengthFrameDecoder Each fixed length is counted as a message socketChannel.pipeline().addLast( new FixedLengthFrameDecoder( 5 )); //5 represents a length of 5 bytes socketChannel.pipeline ().addLast( new StringDecoder()); socketChannel.pipeline().addLast( new
ClientHandler());
}
});
try {
ChannelFuture f = bootstrap.connect( "127.0.0.1" , 8765 ).sync();
// f.channel().writeAndFlush(Unpooled.copiedBuffer("adbcefg".getBytes ()));// More than 5 , in fact, only adbce can be received , and the latter cannot be received because less than 5 lengths
//f.channel ().writeAndFlush(Unpooled.copiedBuffer("adb".getBytes ()));// Less than 5 lengths, this cannot be received, f.channel().writeAndFlush(Unpooled.copiedBuffer ( " adb " .getBytes ())); // Make up for 5 lengths, can receive arrive
f.channel().closeFuture().sync();
workGroup.shutdownGracefully();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Client c1= new Client();
c1.connect();
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.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.string.StringDecoder; public class Client { public void connect() { EventLoopGroup workGroup = new NioEventLoopGroup(); Bootstrap bootstrap = new Bootstrap(); bootstrap.group(workGroup).channel(NioSocketChannel. class) .handler( new ChannelInitializer<SocketChannel>() { protected void initChannel(SocketChannel socketChannel) throws
Exception {
/*// Method 1: Add special characters to the end of the packet // Set the special separator ByteBuf f=Unpooled.copiedBuffer("$_".getBytes()); socketChannel.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, f) );*/ // Method 2 Fixed length key class FixedLengthFrameDecoder Each fixed length is counted as a message socketChannel.pipeline().addLast( new FixedLengthFrameDecoder( 5 )); //5 represents a length of 5 bytes socketChannel.pipeline ().addLast( new StringDecoder()); socketChannel.pipeline().addLast( new
ClientHandler());
}
});
try {
ChannelFuture f = bootstrap.connect( "127.0.0.1" , 8765 ).sync();
// f.channel().writeAndFlush(Unpooled.copiedBuffer("adbcefg".getBytes ()));// More than 5 , in fact, only adbce can be received , and the latter cannot be received because less than 5 lengths
//f.channel ().writeAndFlush(Unpooled.copiedBuffer("adb".getBytes ()));// Less than 5 lengths, this cannot be received, f.channel().writeAndFlush(Unpooled.copiedBuffer ( " adb " .getBytes ())); // Make up for 5 lengths, can receive arrive
f.channel().closeFuture().sync();
workGroup.shutdownGracefully();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Client c1= new Client();
c1.connect();
}
}
ClientHandler
package com.aowin.netty.chaibaoAndNianbao;
import com.aowin.netty.hello.ClientHanler;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
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.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class ClientHandler extends ChannelHandlerAdapter {
private Log logger= LogFactory. getLog(ClientHanler. class);
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
String rev_msg= (String) msg;
logger.info( " 客户端收到的消息 ///"+rev_msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
}
}
import com.aowin.netty.hello.ClientHanler;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
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.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class ClientHandler extends ChannelHandlerAdapter {
private Log logger= LogFactory. getLog(ClientHanler. class);
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
String rev_msg= (String) msg;
logger.info( " 客户端收到的消息 ///"+rev_msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
}
}
Server
package com.aowin.netty.chaibaoAndNianbao;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
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.FixedLengthFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import java.nio.Buffer;
public class Server {
public void bind() {
EventLoopGroup boosGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boosGroup, workGroup)
.channel(NioServerSocketChannel. class)
.option(ChannelOption. SO_BACKLOG, 10)
.option(ChannelOption. CONNECT_TIMEOUT_MILLIS, 2000)
.childHandler( new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel socketChannel) throws Exception {
/*
// 方式一:包尾添加特殊字符
// 设置拆包粘包特殊字符 关键类 DelimiterBasedFrameDecoder
// 当客户端发来的消息每出现一个 “$_” 就算是一段消息
ByteBuf f = Unpooled.copiedBuffer("$_".getBytes());
socketChannel.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, f));//1024 指的是分隔符的长度上限 */
// 设置字符串形式的编解码
// 方式二:固定长度
socketChannel.pipeline().addLast( new FixedLengthFrameDecoder( 5));
socketChannel.pipeline().addLast( new StringDecoder());
socketChannel.pipeline().addLast( new com.aowin.netty.chaibaoAndNianbao.ServerHandler());
}
});
try {
ChannelFuture future = bootstrap.bind( "127.0.0.1", 8765).sync();
future.channel().closeFuture().sync();
boosGroup.shutdownGracefully();
workGroup.shutdownGracefully();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Server s1 = new Server();
s1.bind();
}
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
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.FixedLengthFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import java.nio.Buffer;
public class Server {
public void bind() {
EventLoopGroup boosGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boosGroup, workGroup)
.channel(NioServerSocketChannel. class)
.option(ChannelOption. SO_BACKLOG, 10)
.option(ChannelOption. CONNECT_TIMEOUT_MILLIS, 2000)
.childHandler( new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel socketChannel) throws Exception {
/*
// 方式一:包尾添加特殊字符
// 设置拆包粘包特殊字符 关键类 DelimiterBasedFrameDecoder
// 当客户端发来的消息每出现一个 “$_” 就算是一段消息
ByteBuf f = Unpooled.copiedBuffer("$_".getBytes());
socketChannel.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, f));//1024 指的是分隔符的长度上限 */
// 设置字符串形式的编解码
// 方式二:固定长度
socketChannel.pipeline().addLast( new FixedLengthFrameDecoder( 5));
socketChannel.pipeline().addLast( new StringDecoder());
socketChannel.pipeline().addLast( new com.aowin.netty.chaibaoAndNianbao.ServerHandler());
}
});
try {
ChannelFuture future = bootstrap.bind( "127.0.0.1", 8765).sync();
future.channel().closeFuture().sync();
boosGroup.shutdownGracefully();
workGroup.shutdownGracefully();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Server s1 = new Server();
s1.bind();
}
}
ServerHandler
package com.aowin.netty.chaibaoAndNianbao;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class ServerHandler extends ChannelHandlerAdapter {
private Log logger = LogFactory. getLog(ServerHandler. class);
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.error( " 服务端异常 ", cause);
ctx.close();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
logger.info( " 服务端激活 ");
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
logger.info( " 服务端开始读数据 ");
String rev_msg = (String) msg;
logger.info(rev_msg);
}
@Override
public void channelReadComplete( final ChannelHandlerContext ctx) throws Exception {
logger.info( " 服务端读完数据 ");
ChannelFuture cf = ctx.writeAndFlush(Unpooled. copiedBuffer( "adbcefg".getBytes()));
cf.addListener( new ChannelFutureListener() {
public void operationComplete(ChannelFuture channelFuture) throws Exception {
logger.info( " 客户端收到消息 ");
ctx.close();
}
});
}
}
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class ServerHandler extends ChannelHandlerAdapter {
private Log logger = LogFactory. getLog(ServerHandler. class);
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.error( " 服务端异常 ", cause);
ctx.close();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
logger.info( " 服务端激活 ");
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
logger.info( " 服务端开始读数据 ");
String rev_msg = (String) msg;
logger.info(rev_msg);
}
@Override
public void channelReadComplete( final ChannelHandlerContext ctx) throws Exception {
logger.info( " 服务端读完数据 ");
ChannelFuture cf = ctx.writeAndFlush(Unpooled. copiedBuffer( "adbcefg".getBytes()));
cf.addListener( new ChannelFutureListener() {
public void operationComplete(ChannelFuture channelFuture) throws Exception {
logger.info( " 客户端收到消息 ");
ctx.close();
}
});
}
}