Netty(一) 简单的Client-Server开发+TCP粘包/拆包解决代码(换行与标识符两种)

本节只介绍如何传输String类型的简单的Client-Server模式的Netty代码 和几种处理TCP粘包/拆包的方式

 

1、NettyServer主逻辑

package com.back.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class SimpleNettyServer {

	public static void main(String[] args) {
		int port = 8888;
		EventLoopGroup bossGroup = new NioEventLoopGroup();
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		try {
			ServerBootstrap serverBootstrap = new ServerBootstrap();
			serverBootstrap.group(bossGroup, workerGroup)
			.channel(NioServerSocketChannel.class)
			.option(ChannelOption.SO_BACKLOG, 1024).childHandler(new RouteHandler());
			ChannelFuture future = serverBootstrap.bind(port).sync();
			System.out.println("server start!");
			future.channel().closeFuture().sync();
		} catch (InterruptedException e) {
			
		}finally{
			System.out.println("释放线程池资源!");
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
		}
		
	}
}

2、上面看到的RouteHandler代码

package com.back.server;

import com.back.constant.NettyConstant;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
/**
 * 设置请求 要经过哪些处理的handler  
 * 公共的handler逻辑等 可以在此处添加  如:记录日志、消息编解码等
 * LineBasedFrameDecoder+StringDecoder 来解决TCP粘包拆包问题原理
 * 前者识别换行符,同时设置单行最大字节 所以这两个组合就是按行切换的文本解码器
 * DelimiterBasedFrameDecoder+StringDecoder 则是通过制定分隔符(同时设置最大字节)来区分 每次消息末尾都要加指定分隔符
 * FixedLengthFrameDecoder+StringDecoder 则代表不管怎样 每次读取指定长度 字节的包 不在演示
 * @author back
 *
 */
public class RouteHandler extends ChannelInitializer<SocketChannel> {

	@Override
	protected void initChannel(SocketChannel arg0) throws Exception {
		
		//arg0.pipeline().addLast(new LineBasedFrameDecoder(1024));
		ByteBuf delimiter = Unpooled.copiedBuffer(NettyConstant.DELIMITER.getBytes());
		arg0.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));
		arg0.pipeline().addLast(new StringDecoder());
		arg0.pipeline().addLast(new MessageHandler());
	}

}

3、业务处理的逻辑类MessageHandler

package com.back.server;

import com.back.constant.NettyConstant;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;


/**
 * 真实处理信息的handler
 * @author Administrator
 *
 */
public class MessageHandler extends ChannelHandlerAdapter {

	private RequestHandler handler = RequestHandler.getRequestHandler();
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		String message = (String)msg;
		System.out.println("请求报文 : " + message);
		//String dilimiter = System.getProperty("line.separator");
		String resp = handler.simpleHandlerRequest(message)+NettyConstant.DELIMITER;
		ByteBuf copiedBuffer = Unpooled.copiedBuffer(resp.getBytes());
		ctx.writeAndFlush(copiedBuffer);
	}
	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		ctx.flush();
	}
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		ctx.close();
	}
}

4、自定义的业务逻辑类

package com.back.server;

import java.text.SimpleDateFormat;
import java.util.Date;
/**
 * 随便写了个处理请求 和返回值得逻辑
 * @author back
 *
 */
public class RequestHandler {
 
	private RequestHandler(){};
	private static volatile RequestHandler handler;
	private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ");
	public static RequestHandler getRequestHandler(){
		if(handler == null){
			synchronized (RequestHandler.class) {
				if(null == handler){
					handler = new RequestHandler();
				}
			}
		}
		return handler;
	}
	
	public  String simpleHandlerRequest(String request){
		String response = null;
		switch (request) {
		case "time":
			response = sdf.format(new Date());
			break;

		default:
			break;
		}
		return response == null ? "badReq" :response;
	}
}

5、NettyClient 

package com.back.client;

import com.back.constant.NettyConstant;

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.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.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;

public class SimpleNettyClient {

	public static void main(String[] args) {
		
		NioEventLoopGroup group = new NioEventLoopGroup();
		try {
			Bootstrap bootstrap = new Bootstrap();
			bootstrap.group(group).channel(NioSocketChannel.class)
			.option(ChannelOption.TCP_NODELAY, true)
			.handler(new ClientRouteHandler());
			ChannelFuture future = bootstrap.connect("127.0.0.1", 8888).sync();
			System.out.println("client start!");
			future.channel().closeFuture().sync();
		} catch (InterruptedException e) {
		}finally{
			group.shutdownGracefully();
		}
		
	}
}
class ClientRouteHandler extends ChannelInitializer<SocketChannel>{

	@Override
	protected void initChannel(SocketChannel ch) throws Exception {
		//ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
		ByteBuf delimiter = Unpooled.copiedBuffer(NettyConstant.DELIMITER.getBytes());
		ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));
		ch.pipeline().addLast(new StringDecoder());
		ch.pipeline().addLast(new ClientMessageHandler());
	}
	
}

6、ClientMessageHandler 发送请求和拿到返回报文

package com.back.client;

import com.back.constant.NettyConstant;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;

public class ClientMessageHandler extends ChannelHandlerAdapter {

	//byte[] req = ("time"+System.getProperty("line.separator")).getBytes();
	
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		for (int i = 0; i < 100; i++) {
			byte[] req = ("time"+NettyConstant.DELIMITER).getBytes();
			ByteBuf buf = Unpooled.buffer(req.length);
			buf.writeBytes(req);
			ctx.writeAndFlush(buf);
		}
	}
	
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		
		String response = (String)msg;
		System.out.println("接收到报文:"+response);
	}
	
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		ctx.close();
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值