5. Netty初认识--入门应用-客户端和服务端交互不断输出内容

  |   0 评论   |   0 浏览

SomeServer.java

package club.wujingjian.study;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
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 io.netty.handler.codec.string.StringEncoder;

public class SomeServer {
    public static void main(String[] args) throws InterruptedException {
        NioEventLoopGroup parentGroup = new NioEventLoopGroup();
        NioEventLoopGroup childGroup = new NioEventLoopGroup();

        try{
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(parentGroup,childGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //StringDecoder()字符串解码器,将Channel中的ByteBuf数据解码为String
                            //StringEncoder()字符串编码器,将要写入Channel中的String编码为ByteBuf
                            ch.pipeline().addLast(new StringEncoder()).addLast(new StringDecoder())
                                    .addLast(new SomeServerHandler());
                        }
                    });
            ChannelFuture future = bootstrap.bind(8888).sync();
            System.out.println("服务器已启动");
            future.channel().closeFuture().sync();
        }finally {
            parentGroup.shutdownGracefully();
            childGroup.shutdownGracefully();
        }
    }
}

SomeServerHandler.java

package club.wujingjian.study;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

public class SomeServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //将来自于客户端的数据打印
        System.out.println(ctx.channel().remoteAddress() + ", " + msg);
        //向客户端发送数据
        ctx.channel().writeAndFlush("from server:这里是服务器的响应数据!" + UUID.randomUUID());
        TimeUnit.MICROSECONDS.sleep(500);

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
}

SomeClient.java

package club.wujingjian.study.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

public class SomeClient {

    public static void main(String[] args) throws InterruptedException {
        NioEventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new StringEncoder())
                        .addLast(new StringDecoder())
                        .addLast(new SomeClientHandler());
                    }
                });
            ChannelFuture future = bootstrap.connect("localhost", 8888).sync();
            future.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }
    }
}

SomeClientHandler.java

package club.wujingjian.study.client;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;



public class SomeClientHandler extends SimpleChannelInboundHandler<String> {

    // msg的消息类型与类中的泛型类型是一致的
    //SimpleChannelInboundHandler 中的ChannelRead()方法会自动释放接收到的来自于对方的msg所占有的所有资源.
    //ChannelInboundHandlerAdapter中的ChannelRead()方法不会自动释放接收到的来自于对方的msg所占有的所有资源.

    //以下两种情况建议使用ChannelInboundHandlerAdapter,
    /**
     * 第一种情况:
     *     若对方没有向自己发送数据,则自定义处理器建议继承自ChannelInboundHandlerAdapter,因为若继承自SimpleChannelInboundHandler需要
     *     重写channelRead0()方法,而重写该方法的目的是对来自于对方的数据进行处理.因为对方没发送数据,所以没必要重写channelRead0().
     */

    /**
     * 第二种情况:
     *     若对方向自己发送数据,而自己又需要将该数据再发送给对方,则自定义处理器建议继承自ChannelInboundHandlerAdapter.因为write()方法的
     *     执行是异步的,且SimpleChannelInboundHandler中的channelRead()方法会自动释放掉来自于对方的msg.若write()方法中正在处理msg,而此时
     *     SimpleChannelInboundHandler中的channelread()方法执行完毕了,将msg给释放了,此时就会报错.
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println("from server:来自于服务端" +ctx.channel().remoteAddress()+ " 的消息:" + msg);
        ctx.writeAndFlush("来自于客户端的消息:" + LocalDateTime.now());
        TimeUnit.MICROSECONDS.sleep(500);

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("客户端异常" + ctx.close() );
    }

    //当Channel被激活会触发该方法的执行
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush("1.from client: 客户端的channel被激活了,begin talking");
    }
}

服务端输出:

image.png

客户端输出:

image.png


标题:5. Netty初认识--入门应用-客户端和服务端交互不断输出内容
作者:码农路上
地址:http://wujingjian.club/articles/2020/02/28/1582883899662.html