第一种:自定义规则
比如说我们自己设定$_结尾的数据为一个整体。
看主要代码,大体不变,就多了几行代码。具体先看我上一篇的代码。这里只做修改
server端
b.childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ByteBuf byteBuf = Unpooled.copiedBuffer("$_".getBytes()); ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,byteBuf));//自定义分割标识 ch.pipeline().addLast(new StringDecoder()); //解码类,类似过滤器,处理类接收到数据就不用转到buf再转string了 ch.pipeline().addLast(new MyServerHandler()); } });
服务端处理类
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception{ //读取客户端发来的信息 String m = (String) msg; System.out.println("client:"+m); //向客户端写信息 String name="你好客户端:这是服务端返回的信息!$_"; ctx.writeAndFlush(Unpooled.copiedBuffer(name.getBytes())); }
client端
package com.lzh.netty; 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.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.DelimiterBasedFrameDecoder; import io.netty.handler.codec.string.StringDecoder; /** * Created by 敲代码的卡卡罗特 * on 2018/8/12 21:46. */ public class Client { public static void main(String[] arg){ /** * 如果你只指定了一个EventLoopGroup, * 那他就会即作为一个‘boss’线程, * 也会作为一个‘workder’线程, * 尽管客户端不需要使用到‘boss’线程。 */ Bootstrap b = new Bootstrap(); // (1) EventLoopGroup workerGroup = new NioEventLoopGroup(); b.group(workerGroup); // (2) b.channel(NioSocketChannel.class); // (3) b.option(ChannelOption.SO_KEEPALIVE, true); // (4) b.handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ByteBuf byteBuf = Unpooled.copiedBuffer("$_".getBytes()); ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,byteBuf));//自定义分割标识 ch.pipeline().addLast(new StringDecoder()); //解码类 ch.pipeline().addLast(new MyClientHandler()); } }); try { ChannelFuture f = b.connect("127.0.0.1", 8888).sync(); //向服务端发送信息 f.channel().writeAndFlush(Unpooled.copiedBuffer("你好$_哈哈$_".getBytes())); f.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { workerGroup.shutdownGracefully(); } } }
客户端处理类
package com.lzh.netty; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerContext; import io.netty.util.CharsetUtil; import io.netty.util.ReferenceCountUtil; /** * Created by 敲代码的卡卡罗特 * on 2018/8/12 21:49. */ public class MyClientHandler extends ChannelHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception{ try { //读取服务端发来的信息 String m = (String) msg; // ByteBuf是netty提供的 System.out.println("client:"+m); } catch (Exception e) { e.printStackTrace(); } finally { //当没有写操作的时候要把msg给清空。如果有写操作,就不用清空,因为写操作会自动把msg清空。这是netty的特性。 ReferenceCountUtil.release(msg); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); } }
第二种:定长的分隔符
其实很简单,就是加上一条限制。
ch.pipeline().addLast(new FixedLengthFrameDecoder(5)); //定长的分隔符