springboot Netty搭建與使用 Java與機器通信

Netty是由JBOSS提供的一個java開源框架,現爲 Github上的獨立項目。Netty提供異步的、事件驅動的網絡應用程序框架和工具,用以快速開發高性能、高可靠性的網絡服務器和客戶端程序。

也就是說,Netty 是一個基於NIO的客戶、服務器端編程框架,使用Netty 可以確保你快速和簡單的開發出一個網絡應用,例如實現了某種協議的客戶、服務端應用。Netty相當於簡化和流線化了網絡應用的編程開發過程,例如:基於TCP和UDP的socket服務開發。

我Netty主要是與機器進行通訊 一臺服務對多臺機器

作爲一個開發者,我以業務實現爲主  上代碼

 

NettyServer .java

package com.springboot.exam.controller.netty;
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;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;

/**
 * date: 2019-07-11 11:11
 **/
@Component
public class NettyServer {

    private static final Logger log = LoggerFactory.getLogger(NettyServer.class);
    //boss事件輪詢線程組
    private EventLoopGroup boss = new NioEventLoopGroup();
    //worker事件輪詢線程組
    private EventLoopGroup worker = new NioEventLoopGroup();

    private Channel channel;
    //連接map
    public  static Map<String, ChannelHandlerContext> map = new HashMap<String, ChannelHandlerContext>();

    @Value("${n.port}")
    private Integer port;
    @Value("${n.url}")
    private String url;

    /**
     * 開啓Netty服務
     *
     * @return
     */
    public ChannelFuture start() throws InterruptedException {
        // 1. 創建一個線程組:接收客戶端連接
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        // 2. 創建一個線程組:處理網絡操作
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        // 3. 創建服務器端啓動助手來配置參數
        ServerBootstrap b = new ServerBootstrap();
        b.group(bossGroup,workerGroup)//設置兩個線程組
                .channel(NioServerSocketChannel.class)//5.使用NioServerSocketChannel作爲服務器端通道的實現
                .option(ChannelOption.SO_BACKLOG,1024)//6.設置線程隊列中等待連接的個數
                .childOption(ChannelOption.SO_KEEPALIVE,true)//7.保持活動連接狀態
                .childHandler(new ChannelInitializer<SocketChannel>() {//8.創建一個通道初始化對象
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {//9.往pipeline鏈添加自定義的handler類
                        //socketChannel.pipeline().addLast(new LineBasedFrameDecoder(10010));
                        //字符串解碼和編碼
                        //LineBasedFrameDecoder + StringDecoder 就是一個按行切換的文本解碼器。
                        //socketChannel.pipeline().addLast( new StringDecoder());
                        //socketChannel.pipeline().addLast( new StringEncoder());
                        socketChannel.pipeline().addLast(new NettyServerHandler());
                    }
                });
        ChannelFuture cf = b.bind(port).sync();//綁定端口 非阻塞
        //ChannelFuture cf = b.bind(url, port);
        ChannelFuture channelFuture1 = cf.syncUninterruptibly();//接收連接
        channel = channelFuture1.channel();//獲取通道
        if (channelFuture1 != null && channelFuture1.isSuccess()) {
            log.info("Netty server 服務啓動成功,端口port = {}", port);
        } else {
            log.info("Netty server start fail");
        }
        cf.channel().closeFuture().sync();//異步
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();

        return cf;
    }

    /**
     * 停止Netty服務
     */
    public void destroy() {
        if (channel != null) {
            channel.close();
        }
        worker.shutdownGracefully();
        boss.shutdownGracefully();
        log.info("Netty server shutdown success");
    }

}


重點

NettyServerHandler 

package com.springboot.exam.controller.netty;

import com.springboot.exam.service.LoginService;
import com.springboot.exam.util.DemoHandler;
import com.springboot.exam.util.util;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    
    //存儲全局 
    public static final Map<Object,ChannelHandlerContext> mapsocket = new HashMap<>();

    // 讀取數據事件
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf bufferBuf = (ByteBuf) msg;
        byte[] data = new byte[bufferBuf.readableBytes()];
        bufferBuf.readBytes(data);

        System.out.println("解密前");
        for (byte sss:data) {
            System.out.print(sss+" ");
        }
        System.out.println();

        //業務邏輯  
        //記得一定要存ChannelHandlerContext  
        //後期要通過ChannelHandlerContext  發消息給固定的機器
        mapsocket.put("發送信息過來的機器的主鍵id",ctx);
       
    }


    //發送消息
    //xxs 發送的消息(指令)
    //ss  發送信息過來的機器的主鍵id(可以用其他主鍵代替,只要和上面對應)
    public static void pudate(byte[] xxs,int ss){
            ByteBuf msg = null;
            msg = Unpooled.buffer(xxs.length);
            msg.writeBytes(xxs);
            mapsocket.get(ss).writeAndFlush(msg);

    }


    public static byte[] bl_zjl="000000".getBytes();

    public  byte[] getBl_zjl() {
        return bl_zjl;
    }
    


    @Autowired
    private LoginService loginServers;

    // 數據讀取完畢事件
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        /*byte[] req = getBl_zjl();
        ByteBuf msg = null;
        msg = Unpooled.buffer(req.length);
        msg.writeBytes(req);
        ctx.writeAndFlush(msg);*/

    }

    // 異常發生事件
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close(); //關閉上下文,上下文是所有信息的彙總
        super.exceptionCaught(ctx, cause);
        System.out.println("異常了!!!!!!!!!!!!!!!");
    }

    /**
     * 將指定byte數組以16進制的形式打印到控制檯
     *
     * @param hint
     *            String
     * @param b
     *            byte[]
     * @return void
     */
    public static void printHexString(String hint, byte[] b) {
        System.out.print(hint);
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            System.out.print(hex.toUpperCase() + " ");
        }
        System.out.println("");
    }

    /**
     *
     * @param b
     *            byte[]
     * @return String
     */
    public String Bytes2HexString(byte[] b) {
        String ret = "";
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            ret += " 0x" + hex.toUpperCase();
        }
        return ret;
    }
    /**
     * 將兩個ASCII字符合成一個字節; 如:"EF"–> 0xEF
     *
     * @param src0
     *            byte
     * @param src1
     *            byte
     * @return byte
     */
    public byte uniteBytes(byte src0, byte src1) {
        byte _b0 = Byte.decode("0x" + new String(new byte[] {src0})).byteValue();
        _b0 = (byte) (_b0 << 4);
        byte _b1 = Byte.decode("0x" + new String(new byte[] { src1 })).byteValue();
        byte ret = (byte) (_b0 ^ _b1);
        return ret;
    }

    /**
     * 將指定字符串src,以每兩個字符分割轉換爲16進制形式 如:"2B44EFD9" –> byte[]{0x2B, 0×44, 0xEF,
     * 0xD9}
     *
     * @param src
     *            String
     * @return byte[]
     */
    public byte[] HexString2Bytes(String src) {
        if (null == src || 0 == src.length()) {
            return null;
        }
        byte[] ret = new byte[src.length() / 2];
        byte[] tmp = src.getBytes();
        for (int i = 0; i < (tmp.length / 2); i++) {
            ret[i] = uniteBytes(tmp[i * 2], tmp[i * 2 + 1]);
        }
        return ret;
    }
    public static final Map<Object,String> sdsf = new HashMap<>();
    
    public static void main(String[] args){
        sdsf.put("11","123");
        sdsf.put("22","123456");
        sdsf.put("23","123456789");
        System.out.println(sdsf.get("11"));
        System.out.println(sdsf.get("22"));
        System.out.println(sdsf.get("23"));
    }

}

NettyClientHandler.java

 

package com.springboot.exam.controller.netty;

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

public class NettyClientHandler extends ChannelInboundHandlerAdapter {

    // 通道就緒事件
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("Client: "+ctx);
        ctx.writeAndFlush(Unpooled.copiedBuffer("00 0D BC BB BC BC BF AC 82 DD 87 5C C9 01 05", CharsetUtil.UTF_8));
        ctx.writeAndFlush(Unpooled.copiedBuffer("00 0D BC BB BC BC BF AC 82 DD 87 5C C9 01 05", CharsetUtil.UTF_8));
    }

    // 讀取數據事件
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf)msg;
        System.out.println("服務器端發來的消息:"+buf.toString(CharsetUtil.UTF_8));
    }

}
NettyClient.java
package com.springboot.exam.controller.netty;

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

public class NettyClient {

    public static void main(String[] args) throws Exception {


        // 1. 創建一個線程組
        EventLoopGroup group = new NioEventLoopGroup();
        // 2. 創建客戶端的啓動助手,完成相關配置
        Bootstrap b = new Bootstrap();
        b.group(group) // 3.設置線程組
                .channel(NioSocketChannel.class) //4.設置客戶端通道的實現類
                .handler(new ChannelInitializer<SocketChannel>() {// 5.創建一個通道初始化對象
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast(new NettyClientHandler());//6.往pipeline鏈中添加自定義的handler
                    }
                });
        System.out.println("........Client is ready............");
        // 7.啓動客戶端去連接服務器端,connect方法是異步的 ,sync方法是同步阻塞的
        ChannelFuture cf = b.connect("127.0.0.1",10010).sync();
        // 8.關閉連接(異步非阻塞)
        cf.channel().closeFuture().sync();
    }
}

 

Application.java

package com.springboot.exam;

import com.springboot.exam.controller.netty.NettyServer;
import io.netty.channel.ChannelFuture;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;


import org.springframework.boot.CommandLineRunner;


/**
 * ClassName: SpringBootApplication
 * description:
 * author:
 * date: 2018-09-30 09:15
 **/
@org.springframework.boot.autoconfigure.SpringBootApplication//@EnableAutoConfiguration @ComponentScan
public class ExamApplication implements CommandLineRunner  {

    public static void main(String[] args) {
        SpringApplication.run(ExamApplication.class, args);
    }
    @Autowired
    NettyServer nettyServer;

    @Override
    public void run(String... args) throws Exception {
        ChannelFuture start = nettyServer.start();
        Runtime.getRuntime().addShutdownHook(new Thread(){
            @Override
            public void run() {
                nettyServer.destroy();
            }
        });
        start.channel().closeFuture().syncUninterruptibly();

    }



}

 

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