美文网首页netty学习
netty学习(2)--用netty搭建搭建时间服务器

netty学习(2)--用netty搭建搭建时间服务器

作者: 飞白非白 | 来源:发表于2019-01-30 16:01 被阅读2次

开发环境搭建

需要说明的是笔者使用的编辑器是idea,同时还要安装gradle插件,因为学习netty的过程是和gradle一起的,所以后面的netty学习都会使用gradle

gradle环境搭建

  1. 官网下载 gradle

  2. .bash_profile 文件中配置Gradle环境变量

GRADLE_HOME=/Users/sirtian/Documents/environment/gradle-5.0
PATH=:$GRADLE_HOME/bin:$PATH:.
export GRADLE_HOME
  1. 在控制台使用source .bash_profile命令对修改后的配置文件进行更新

  2. 在控制 台使用gradle -version命令查看是否配置成功,如果成功输出gradle的版本则说明配置成功

使用idea创建gradle项目

WX20190130-140814@2x.png

此处创建完毕后,需要在gradle的配置文件中添加netty的依赖文件,因为后期会对源码进行分析,所以此处下载包含源码的jar包,可以在此处找到gradle的依赖并将其加到gradle配置中,如下

WX20190130-141709@2x.png

服务端代码

TimeServer.java

package com.sirTian;

import com.sun.security.ntlm.Server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.net.SocketOption;


public class TimeServer {
    private class ChildChannelHandler extends ChannelInitializer<SocketChannel>{
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            ch.pipeline().addLast(new TimeServerHandler());
        }
    }

    public void bind(int port) throws Exception{

        // EventLoopGroup是线程组,这里包含两个线程组,分别用于监听客户端连接和
        // 处理客户端读写事件
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workgroup = new NioEventLoopGroup();

        try{
            // ServerBootstrap 是服务端启动辅助类
            ServerBootstrap bootstrap = new ServerBootstrap();

            // group方法将两个线程组作为参数绑定到启动类中,channel方法绑定channel,对于server这里绑定
            // NioServerSocketChannel,childHandler方法绑定到具体的处理方法
            bootstrap.group(bossGroup,workgroup).channel(NioServerSocketChannel.class)
                    .childHandler(new ChildChannelHandler());

            // 先调用bind方法绑定监听端口,然后调用sync方法,这是一个同步方法,用于等待绑定操作完成
            // future对象类似于Jdk的Future
            ChannelFuture future = bootstrap.bind(8080).sync();

            future.channel().closeFuture().sync();
        }finally {

            //  关闭线程组关联的资源
            bossGroup.shutdownGracefully();
            workgroup.shutdownGracefully();
        }



    }

    public static void main(String[] args) throws Exception{
        new TimeServer().bind(8080);
    }
}

TimeServerHandler.java

package com.sirTian;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class TimeServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        ByteBuf byteBuf = (ByteBuf)msg;

        byte[] req = new byte[byteBuf.readableBytes()];

        byteBuf.readBytes(req);

        String body = new String(req,"UTF-8");

        System.out.println("QUERY TIME ORDER:"+body);

        String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body)?new java.util.Date(System.
                currentTimeMillis()).toString():"Bad order";

        ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());

        ctx.write(resp);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

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

客户端代码

TimeClient.java

package com.sirTian;

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
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;


public class TimeClient {
    private class ChildChannelHandler extends ChannelInitializer<SocketChannel>{
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            ch.pipeline().addLast(new TimeServerHandler());
        }
    }

    public void connect(int port) throws Exception{
        // 这里不同于服务器端,因为只需要连接即可,故只用创建一个线程组
        EventLoopGroup 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 TimeClientHandler());
                        }
                    });

            // 这里区别于服务端的bind方法
            ChannelFuture future = bootstrap.connect("localhost",8080).sync();

            future.channel().closeFuture().sync();
        }finally {
            group.shutdownGracefully();
        }



    }

    public static void main(String[] args) throws Exception{
        new TimeClient().connect(8080);
    }
}

TimeClientHandler.java

package com.sirTian;

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

public class TimeClientHandler extends ChannelInboundHandlerAdapter {

    private ByteBuf firstMessage;



    public TimeClientHandler() {

        byte[] request = "QUERY TIME ORDER".getBytes();

        firstMessage = Unpooled.buffer(request.length);

        firstMessage.writeBytes(request);

    }



    @Override

    public void channelActive(ChannelHandlerContext ctx) {

        ctx.writeAndFlush(firstMessage);

    }



    @Override

    public void channelRead(ChannelHandlerContext ctx, Object msg)

            throws Exception {

        ByteBuf byteBuf = (ByteBuf) msg;

        byte[] req = new byte[byteBuf.readableBytes()];

        byteBuf.readBytes(req);

        String body = new String(req, "UTF-8");

        System.out.println("Now is:" + body);

    }



    @Override

    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {

        // 释放资源

        ctx.close();

    }


}

运行结果

WX20190130-155812@2x.png WX20190130-155820@2x.png

总结

通过以上代码可以大概了解到使用netty创建应用的过程,以及其相对于jdk原生api创建应用程序的便捷性,后面会慢慢接触netty中更加高级的东西。

相关文章

网友评论

    本文标题:netty学习(2)--用netty搭建搭建时间服务器

    本文链接:https://www.haomeiwen.com/subject/qdxcsqtx.html