Netty简单实现TCP代理,实例为MYSQL代理

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
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.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

public class TcpServer {

    private Bootstrap bootstrap;
    private ServerBootstrap server;

    private NioEventLoopGroup bossgroup;
    private NioEventLoopGroup workgroup;

    public void init() {
        this.bossgroup = new NioEventLoopGroup();
        this.workgroup = new NioEventLoopGroup();
        this.server = new ServerBootstrap();
        this.bootstrap = new Bootstrap();
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.group(bossgroup);
        this.server.group(bossgroup, workgroup);
        server.channel(NioServerSocketChannel.class)
                //处理打印日志
                .handler(new LoggingHandler(LogLevel.INFO))
                .childHandler(new ChannelInitializer() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        //服务端channel,将服务端的数据发送给客户端,所以构造函数参数要传入客户端的channel
                        ch.pipeline().addLast("serverHandler", new DataHandler(getClientChannel(ch)));
                    }
                }).option(ChannelOption.SO_BACKLOG, 1024)
                // SO_SNDBUF发送缓冲区,SO_RCVBUF接收缓冲区,SO_KEEPALIVE开启心跳监测(保证连接有效)
                .option(ChannelOption.SO_SNDBUF, 16 * 1024)
                .option(ChannelOption.SO_RCVBUF, 16 * 1024)
                .option(ChannelOption.SO_KEEPALIVE, true);
        server.bind(9999).syncUninterruptibly()
                .addListener((ChannelFutureListener) channelFuture -> {
                    if (channelFuture.isSuccess()) {
                        System.out.println("服务器启动成功");
                    } else {
                        System.out.println("服务器启动失败");
                    }
                });
    }

    private Channel getClientChannel(SocketChannel ch) throws InterruptedException {
        this.bootstrap
                .handler(new ChannelInitializer() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) {
                        //客户端端channel,客户端返回的数据给服务端,所以构造函数参数要传入服务端的channel
                        socketChannel.pipeline().addLast("clientHandler", new DataHandler(ch));
                    }
                });
        ChannelFuture sync = bootstrap.connect("127.0.0.1", 3306).sync();
        return sync.channel();
    }


    public static void main(String[] args) {
        TcpServer tcpServer = new TcpServer();
        tcpServer.init();
    }
}

数据交换handler 继承ChannelInboundHandlerAdapter类 中channelRead方法获取服务端数据和客户端数据,打通服务端和客户端互相交换数据。

原理是通过两者各自拿到对方channel互相发送数据

import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;

public class DataHandler extends ChannelInboundHandlerAdapter {

    private Channel channel;

    public DataHandler(Channel channel) {
        this.channel = channel;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // 获取读取的数据, 是一个缓冲。
        ByteBuf readBuffer = (ByteBuf) msg;
        System.out.println("get data: " + readBuffer.toString(CharsetUtil.UTF_8));
        //这里的复位不能省略,不然会因为计数器问题报错.
        readBuffer.retain();
        //将数据发到远程客户端那边
        channel.writeAndFlush(readBuffer);
    }
}

你可能感兴趣的:(java,java)