Java NIO的netty实现

本文介绍了Java NIO在Netty中的应用,通过服务端和客户端的实例展示了如何处理TCP的半包读写问题。内容包括TimeServer和TimeClient的改造,使用DelimiterBasedFrameDecoder和FixedLengthFrameDecoder进行消息解码,以及EchoServer和EchoClient的实现,旨在解决粘包和拆包问题。
摘要由CSDN通过智能技术生成

 

服务端:

package netty;

import io.netty.bootstrap.ServerBootstrap;
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.NioServerSocketChannel;

/**
 * 时间服务器,当有客户端请求时,返回服务端当前时间
 */

public class TimeServer {

    public void bind(int port){

        //NioEventLoopGroup是一个线程组,它包含了一组NIO线程,
        // 这里的两个线程组一个是用于服务端接受客户端的连接,
        // 另一个用于SocketChannel的网络读写
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            //netty用于启动NIO服务端的辅助启动类
            ServerBootstrap b = new ServerBootstrap();

            //设置线程组
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)//设置channel
                    .option(ChannelOption.SO_BACKLOG, 1024)//设置channel的TCP参数
                    .childHandler(new ChildChannelHandler());//绑定IO事件处理类

            //绑定监听端口,调用同步阻塞方法等待绑定完成
            ChannelFuture f = b.bind(port).sync();
            //阻塞,等待服务端链路关闭后main函数才退出
            f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            //优雅退出,释放跟shutdownGracefully相关联的所有资源
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    private class ChildChannelHandler extends ChannelInitializer<SocketChannel>{

        @Override
        protected void initChannel(SocketChannel serverSocket) throws Exception {
            //增加时间处理类
        serverSocket.pipeline().addLast(new TimeServerHandler());
        }
    }

    public static void main(String[] args) {
        int port = 8080;
        new TimeServer().bind(port);
    }
}

服务端Handler:
package netty;


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

import java.util.Date;


/**
 * 对网络事件进行读写操作
 */
public class TimeServerHandler extends ChannelHandlerAdapter {

    /**
     * 当异常发生时
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        //super.exceptionCaught(ctx, cause);
        ctx.close();
    }

    /**
     * 读取缓冲区里面的数据,处理并返回
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //super.channelRead(ctx, msg);
        ByteBuf buf = (ByteBuf) msg;
        //buf.readableBytes()返回缓冲区可读的字节数
        byte [] bytes = new byte[buf.readableBytes()];
        //读取缓冲区的数据至byte数组
        buf.readBytes(bytes);
        String data = new String(bytes,"UTF-8");
        String currentTime = "query time order".equals(data)? new Date(System.currentTimeMillis()).toString(): "bad order";
        //复制bytes数组的内容,构造一个缓冲区对象ByteBuf
        ByteBuf rsp = Unpooled.copiedBuffer(currentTime.getBytes());
        //异步发送消息给客户端
        ctx.write(rsp);
    }

    /**
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
       // super.channelReadComplete(ctx);
        //ctx.write(rsp)发送消息时不是马上发送,而是将消息发送到发送缓冲区,等到读完成后
        //再调用flush方法将发送缓冲区的消息全部写到SocketChannel中,发送给客户端
        ctx.flush();
    }
}

客户端:

package netty;

import io.netty.bootstrap.Bootstrap;
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;

/**
 * netty的客户端
 */

public class TimeClient {

    public void connect(String host, int port){

        //NioEventLoopGroup是一个线程组,它包含了一组NIO线程
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            //客户端辅助启动类
            Bootstrap b = new Bootstrap();

            //设置线程组
            b.group(group)
                    .channel(NioSocketChannel.class)//设置Channel
                    .option(ChannelOption.TCP_NODELAY, true)//设置TCP的参数
                    .handler(new ChannelInitializer<SocketChannel>() {//匿名内部类设置handler
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new TimeClientHandler());
                        }
                    });
            //异步连接客户端,同步阻塞直到连接成功
        Chann
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值