Netty 出入站处理器 实现 客户与服务器通信

Server:

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
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 java.nio.charset.Charset;
import java.util.Base64;
import java.util.Date;

public class Server {
    public static void main(String[] args) throws InterruptedException {
        ServerBootstrap serverBootstrap = new ServerBootstrap();

        EventLoopGroup boss = new NioEventLoopGroup(1);
        EventLoopGroup worker = new NioEventLoopGroup(1);
        //1、配置监听线程和处理线程
        serverBootstrap.group(boss,worker);
        //2、为监听线程设置通道类型(监听线程设置为Nio,工作就自动和它匹配了吗?)
        serverBootstrap.channel(NioServerSocketChannel.class);
        //3、为监听线程的通道设置TCP属性
        serverBootstrap.option(ChannelOption.SO_BACKLOG, 2048);//socket接收队列大小(因为accept()也只能一个一个来,其余的缓冲起来)
        serverBootstrap.option(ChannelOption.SO_REUSEADDR, true);//避免端口冲突(允许共用该端口,这个在服务器程序中比较常使用)
        serverBootstrap.option(ChannelOption.TCP_NODELAY, true); // 关闭TCP的小流合并,保证消息的及时性(禁止使用Nagle算法)
        //4、为工作线程的通道设置TCP属性
        serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);//该连接长时间没动静就自动关闭
        serverBootstrap.childOption(ChannelOption.SO_LINGER,1);//数据发送完成,连接才能关闭(socket.close()会阻塞一下)
        //5、为监听线程添加 处理类
        serverBootstrap.handler(new ChannelInitializer<NioServerSocketChannel>() {
            @Override
            protected void initChannel(NioServerSocketChannel nioServerSocketChannel) throws Exception {
                ChannelPipeline pipeline=nioServerSocketChannel.pipeline();
                pipeline.addLast();//不需要处理什么吧
            }
        });
        //6、为工作线程添加 处理类
        serverBootstrap.childHandler(new ChannelInitializer<NioSocketChannel>() {
            @Override
            protected void initChannel(NioSocketChannel channel) throws Exception {
                //获取工作线程 通道 的处理类管道(可以在管道里添加各种处理类,进行数据处理)
                ChannelPipeline pipeline = channel.pipeline();
                pipeline.addLast(new SimpleInHandlerA());
                pipeline.addLast(new SimpleInHandlerB());
                pipeline.addLast(new SimpleOutHandlerA());
                pipeline.addLast(new SimpleOutHandlerB());
                pipeline.addLast(new SimpleOutHandlerC());
                pipeline.addLast(new SimpleInHandlerC());


            }
        });
        //7、服务器配置完毕,绑定端口,即可启动。bind后面如果.sync()就同步等待绑定成功或失败,但这里用监听器,可以不阻塞在这。
        ChannelFuture future = serverBootstrap.bind(8080).addListener(new ChannelFutureListener() {
            public void operationComplete (ChannelFuture channelFuture) throws Exception {
                if (channelFuture.isSuccess()) {
                    System.out.println("端口绑定成功");
                    Channel channel = channelFuture.channel();//获取到的是ServerSocketChannel
                    //channel.close();//刚绑定成功就关闭通道,哈哈,客户端就无法连接了。
                } else {
                    System.out.println("端口绑定失败");
                }
            }
        });
        //8、监听通道服务通道是否关闭,不会阻塞在这。
        future.channel().closeFuture().addListener(new ChannelFutureListener() {
            public void operationComplete (ChannelFuture channelFuture) throws Exception {
                System.out.println("服务通道已经关闭");
            }
        });
        System.out.println("服务器启动完成,已有两个线程处于轮询中,主线程可以结束,或做其它事情");
    }
}

class SimpleInHandlerA extends ChannelInboundHandlerAdapter{
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("A被回调");
        super.channelRead(ctx,msg);
    }
}
class SimpleInHandlerB extends ChannelInboundHandlerAdapter{
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("B被回调");
        ctx.fireChannelRead("不给C原始数据");
    }
}
class SimpleInHandlerC extends ChannelInboundHandlerAdapter{
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("C被回调");
        System.out.println(msg);
        ByteBuf buffer = ctx.alloc().buffer();
        byte[] bytes = ("我是服务器").getBytes(Charset.forName("utf-8"));
        buffer.writeBytes(bytes);
        ctx.writeAndFlush(buffer);
        super.channelRead(ctx,msg);
    }
}
class SimpleOutHandlerA extends ChannelOutboundHandlerAdapter{
    @Override
    public void write(ChannelHandlerContext ctx,Object msg,ChannelPromise promise) throws Exception {
        System.out.println("outA被回调");
        ctx.writeAndFlush(msg);//写给客户端
        //super.write(ctx,msg,promise);不能在传播了
    }
}
class SimpleOutHandlerB extends ChannelOutboundHandlerAdapter{
    @Override
    public void write(ChannelHandlerContext ctx,Object msg,ChannelPromise promise) throws Exception {
        System.out.println("outB被回调");
        super.write(ctx,msg,promise);
    }
}
class SimpleOutHandlerC extends ChannelOutboundHandlerAdapter{
    @Override
    public void write(ChannelHandlerContext ctx,Object msg,ChannelPromise promise) throws Exception {
        System.out.println("outC被回调");
        super.write(ctx,msg,promise);
    }
}

Client:


import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.nio.charset.Charset;
import java.util.Date;


public class Client {
    public static void main(String[] args) {
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap
                .group(workerGroup)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) {
                        ch.pipeline().addLast(new FirstClientHandler());
                    }
                });
        // 4.建立连接
        ChannelFuture future=bootstrap.connect("127.0.0.1", 8080).addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                if (channelFuture.isSuccess()) {
                    System.out.println("连接成功!");
                } else {
                    System.err.println("连接失败!");
                }
            }
        });
        future.channel().closeFuture().addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                workerGroup.shutdownGracefully();//通道关闭了,线程也就没有用了,也关闭。
            }
        });

    }
}
class FirstClientHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        //channelActive()方法会在客户端与服务器建立连接后自动调用,(就自动调用一次吗?那我如何各种读写)
        System.out.println("客户端发送消息...");
        ByteBuf buffer = getByteBuf(ctx);
        ctx.channel().writeAndFlush(buffer);
    }
    private ByteBuf getByteBuf(ChannelHandlerContext ctx) {
        // 1. 获取二进制抽象 ByteBuf
        ByteBuf buffer = ctx.alloc().buffer();
        // 2. 准备数据,指定字符串的字符集为 utf-8
        byte[] bytes = ("【客户端】:这是客户端发送的消息:"+new Date()).getBytes(Charset.forName("utf-8"));
        // 3. 填充数据到 ByteBuf
        buffer.writeBytes(bytes);
        return buffer;
    }
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        //服务端发来消息时自动调用
        ByteBuf byteBuf = (ByteBuf) msg;
        System.out.println(byteBuf.toString(Charset.forName("utf-8")));
        ctx.channel().close();//收到回复我就下线
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值