Netty入門(二)-------HelloWord

Netty入門(一)——爲什麼使用Netty

上篇簡單介紹了下爲什麼使用Netty,這篇我們將簡單的搭個HelloWord。
在Netty使用手冊中說了世界上最簡單的協議不是”Hello,World!”,是DISCARD,他是一種丟棄了所有接受到的數據,並不做有任何的響應的協議,本文中就不已拋棄協議爲藍本了,我們就簡單搭個服務端、客戶端。
客戶端發送信息、服務端接收處理並返回給客戶端結果。
整個demo有四個類:
總覽
當然netty的maven依賴也要加入:

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

整個準備情況基本完成。
服務器端代碼:

package com.herman.helloWord;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * @author hsh
 * @create 2018-05-08 18:12
 **/
public class Service {
    public static final int port = 888;
    public static final String ip = "localhost";

    public static void main(String[] args) throws InterruptedException {
        System.out.println("服務端啓動...");
        //1 初始化兩個線程組
        //一個是用於處理服務器端接收客戶端連接的
        //一個是進行網絡通信的(網絡讀寫的)
        NioEventLoopGroup pGroup = new NioEventLoopGroup();
        NioEventLoopGroup cGroup = new NioEventLoopGroup();

        //2 創建輔助工具類 用於服務器通道的一系列配置
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(pGroup, cGroup)//綁定兩個線程組
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, 1024)//設置TCP緩存大小
                .option(ChannelOption.SO_SNDBUF, 32 * 1024)//設置發送緩存大小
                .option(ChannelOption.SO_RCVBUF, 32 * 1024)//設置接收緩存大小
                .option(ChannelOption.SO_KEEPALIVE, true)//保持連接
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        //3 配置具體業務處理邏輯(可多個)
                        socketChannel.pipeline().addLast(new ServerHanler());
                    }
                });
        //綁定
        ChannelFuture future = bootstrap.bind(port).sync();
        //等待關閉
        future.channel().closeFuture().sync();
        //釋放管道
        pGroup.shutdownGracefully();
        cGroup.shutdownGracefully();
    }
}

服務端中對應的業務邏輯處理ServerHanler代碼:

package com.herman.helloWord;

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

/**
 * @author hsh
 * @create 2018-05-08 18:39
 **/
public class ServerHanler extends ChannelHandlerAdapter {

    //激活時調用
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("server channel active...");
    }

    //讀取
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //從內存中獲取消息引用地址
        ByteBuf byteBuf = (ByteBuf) msg;
        //生成內存數組
        byte[] req = new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(req);//copy數據到內存
        String body = new String(req, "UTF-8");
        System.out.println("Server:" + body);
        String response = "服務器返回給客戶端:" + body;
        //返回給客戶端
        ctx.writeAndFlush(Unpooled.copiedBuffer(response.getBytes()));
    }

    //讀取完成
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("服務端讀完了");
        ctx.flush();
    }

    //出現異常
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
        System.out.println("出現了異常");
        throw new RuntimeException("出現了錯誤:", cause);
    }
}

以上服務端搭建完成,定義了兩個NioEventLoopGroup 並使用輔助工具ServerBootstrap來初始化了一個服務端,並通過childHandler方法定義了處理業務的ServerHanler 。
在ServerHanler 中繼承了ChannelHandlerAdapter 並重寫了其中幾個主要的方法。
客戶端代碼:

package com.herman.helloWord;

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

/**
 * @author hsh
 * @create 2018-05-09 9:25
 **/
public class Client {
    public static void main(String[] args) throws InterruptedException {
        NioEventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast(new ClientHandler());
                    }
                });
        ChannelFuture future = bootstrap.connect(Service.ip, Service.port).sync();
        Thread.sleep(1000);
        future.channel().writeAndFlush(Unpooled.copiedBuffer("777".getBytes()));
        future.channel().writeAndFlush(Unpooled.copiedBuffer("666".getBytes()));
        Thread.sleep(2000);
        future.channel().writeAndFlush(Unpooled.copiedBuffer("888".getBytes()));

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

客戶端的業務處理類

package com.herman.helloWord;

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

/**
 * @author hsh
 * @create 2018-05-09 9:27
 **/
public class ClientHandler extends ChannelHandlerAdapter {

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client channel active...");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        try {
        ByteBuf byteBuf = (ByteBuf) msg;
        byte[] req = new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(req);
        String body = new String(req, "UTF-8");
        System.out.println("Client :" + body );
        String response="收到服務端返回的信息:"+body;
        }finally {
            ReferenceCountUtil.release(msg);
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("客戶端讀完了");
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
        throw new RuntimeException("客戶端出現了異常:", cause);
    }
}

客戶端的代碼基本與服務端一致,主要區別是服務端初始化時指定的是NioServerSocketChannel,客戶端是NioSocketChannel。服務端輔助類是調用bind、客戶端是connect。
業務邏輯是客戶端向服務端發送三次數據,服務端接收之後會返回給客戶端相應,客戶端輸出服務器返回的數據。
啓動先啓動服務端,再啓動客戶端,運行效果如下:
服務端:
這裏寫圖片描述
客戶端:
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章