netty 之helloworld

netty编程之helloworld

一: 前言

  Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。

二: 为什么学?

  netty封装了socket,简化了socket编程的操作,因为项目中要对接硬件,所以苦逼的我就来学了......

三: 正文

  3.1 netty是建立在服务端与客户端之间的,所以需要建立两端的代码

  3.2 建立工程,导入maven依赖,这里导入的为5.x版本,如果导入的是4.x版本,下面的代码中无法@Override channelRead方法,即4.x版本与5.x版本的差异

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>5.0.0.Alpha2</version>
</dependency>

  3.3 建立服务端代码,监听对应的端口

    3.3.1 建立服务端处理逻辑

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelHandler.Sharable;
import java.nio.charset.StandardCharsets;
/**
 * 服务端处理逻辑
 */
@Sharable
public class Server4HelloWorldHandler extends ChannelHandlerAdapter {
    /**
     * 用户处理读取数据请求的逻辑
     * @param ctx 包含与客户端建立连接的资源,如: 对应的channel
     * @param msg 读取到的数据,默认类型为ByteBuf.是对ByteBuffer的封装
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx,Object msg) throws Exception {
        ByteBuf readBuffer = (ByteBuf) msg;
        byte[] tempDatas = new byte[readBuffer.readableBytes()];
        readBuffer.readBytes(tempDatas);
        String message = new String(tempDatas, StandardCharsets.UTF_8);
        System.out.println("from client :" + message);

        if("exit".equals(message)){
            ctx.close();
            return;
        }
        String line = "server message to client";
        //如果调用的是write方法,不会刷新缓冲,缓冲中的数据不会发送到客户端,必须再次调用flush方法
        ctx.writeAndFlush(Unpooled.copiedBuffer(line.getBytes(StandardCharsets.UTF_8)));
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("server exceptionCaught method run ..... ");
        ctx.close();
    }
}

    3.3.2 建立服务端,监听对应的端口

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;

/**
 * netty 服务端
 */
public class Server4HelloWorld {

    /**
     * 监听线程组,监听客户端请求
     */
    private EventLoopGroup acceptorGroup;
    /**
     * 处理客户端相关操作线程组,负责处理与客户端的数据通讯
     */
    private EventLoopGroup clientGroup;

    private ServerBootstrap bootstrap;

    public Server4HelloWorld(){
        init();
    }

    private void init() {
        acceptorGroup = new NioEventLoopGroup();

        clientGroup = new NioEventLoopGroup();

        bootstrap = new ServerBootstrap();
        //绑定线程组
        bootstrap.group(acceptorGroup,clientGroup);
        //设置通讯模式为NIO
        bootstrap.channel(NioServerSocketChannel.class);
        //设置缓冲区大小
        bootstrap.option(ChannelOption.SO_BACKLOG,1024);
        //SO_SNDBUF 发送缓冲区,SO_RCVBUF接收缓冲区,
        //SO_KEEPALIVE 开启心跳监测(保证连接有效)
        bootstrap.option(ChannelOption.SO_SNDBUF,16*1024)
                .option(ChannelOption.SO_RCVBUF,16*1024)
                .option(ChannelOption.SO_KEEPALIVE,true);
    }

    /**
     * 监听处理逻辑
     * @param port 监听端口
     * @param acceptorHandlers 处理器,如何处理客户端请求
     * @return ChannelFuture
     * @throws InterruptedException
     */
    public ChannelFuture doAccept(int port, final ChannelHandler ... acceptorHandlers) throws InterruptedException {
        /**
         * childHandler 使bootstrap 独有的方法,是用于提供处理对象的
         * 可以一次性添加若干个处理逻辑,是类似责任链模式处理方式。
         * 增加A,B两个处理逻辑,在处理客户端请求数据的时候,根据A->B 顺序依次处理
         * ChannelInitializer 用于提供处理器的模型对象
         *  其中定义了 initChannel方法,用于初始化处理逻辑责任链的。
         *  可以保证服务端的bootstrap只初始化一次处理器,提供处理逻辑的重用,避免反复创建处理器对象,节约资源
         */
        bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                socketChannel.pipeline().addLast(acceptorHandlers);
            }
        });
        //bind 绑定端口,可以绑定多个端口
        //sync 开启监听,返回ChannelFuture,代表监听成功后的一个对应的未来结果
        //可以使用此对象实现后续的服务器和客户端的交互
        return bootstrap.bind(port).sync();
    }

    /**
     * shutdownGracefully 安全关闭方法,保证不抛弃任何一个已接收的客户端请求
     */
    public void release(){
        this.acceptorGroup.shutdownGracefully();
        this.clientGroup.shutdownGracefully();
    }

    public static void main(String[] args) {
        ChannelFuture future = null;
        Server4HelloWorld server = null;

        try {
            server = new Server4HelloWorld();
            future = server.doAccept(9999,new Server4HelloWorldHandler());
            System.out.println("server started");
            //关闭连接
            //future.channel().close().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            if(null!=future){
                try {
                    future.channel().closeFuture().sync();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            if(null!=server){
                server.release();
            }
        }
    }
}

  3.4 建立客户端代码,连接服务器对应的端口

    3.4.1 建立客户端处理逻辑

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil;

import java.lang.ref.Reference;
import java.nio.charset.StandardCharsets;

public class Client4HelloWorldHandler extends ChannelHandlerAdapter {


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        try {
            ByteBuf readBuffer = (ByteBuf) msg;
            byte[] tempDatas = new byte[readBuffer.readableBytes()];
            readBuffer.readBytes(tempDatas);
            String message = new String(tempDatas, StandardCharsets.UTF_8);
            System.out.println(" from server " + message);
        }finally {
            //用于释放缓存,防止内存溢出
            ReferenceCountUtil.release(msg);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("client exceptionCaught method run .....");
        ctx.close();
    }
}

    3.4.2 建立客户端,连接对应的服务器端口

public class Client4HelloWorld {
    private EventLoopGroup group;

    private Bootstrap bootstrap;

    public Client4HelloWorld(){
        init();
    }

    private void init(){
        group = new NioEventLoopGroup();
        bootstrap = new Bootstrap();

        bootstrap.group(group);

        bootstrap.channel(NioSocketChannel.class);
    }

    public ChannelFuture doRequest(String host, int port, final ChannelHandler ... handlers) throws InterruptedException {
        /**
         * 客户端的bootstrap没有childHandler,只有handler
         *
         * 在客户端必须绑定处理器,也就是必须绑定handler方法。
         * 服务器必须绑定处理器,必须绑定childHandler方法
         */
        this.bootstrap.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                socketChannel.pipeline().addLast(handlers);
            }
        });
        //connect 连接
        return this.bootstrap.connect(host, port).sync();
    }

    public void release(){
        this.group.shutdownGracefully();
    }

    public static void main(String[] args) {

        Client4HelloWorld client = null;
        ChannelFuture future = null;
        try{
            client = new Client4HelloWorld();
            future = client.doRequest("localhost",9999,new Client4HelloWorldHandler());
            Scanner s = null;
            while (true){
                s = new Scanner(System.in);

                System.out.println("enter the message 'exit' to exit");
                String line = s.nextLine();
                if("exit".equals(line)){
                    //addListener 增加监听,当条件满足,触发监听器
                    //ChannelFutureListener.CLOSE 关闭的监听器,代表ChannelFuture执行返回后,关闭连接
                    future.channel().writeAndFlush(Unpooled.copiedBuffer(line.getBytes(StandardCharsets.UTF_8)))
                            .addListener(ChannelFutureListener.CLOSE);
                    break;
                }
                future.channel().writeAndFlush(Unpooled.copiedBuffer(line.getBytes(StandardCharsets.UTF_8)));
                TimeUnit.SECONDS.sleep(1);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(null != future){
                try {
                    future.channel().closeFuture().sync();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            if(null != client){
                client.release();
            }
        }
    }

}

  3.5 运行测试

    

转载于:https://www.cnblogs.com/zhanyifan/p/11054738.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值