springboot Netty搭建与使用 Java与机器通信

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

也就是说,Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户、服务端应用。Netty相当于简化和流线化了网络应用的编程开发过程,例如:基于TCP和UDP的socket服务开发。

我Netty主要是与机器进行通讯 一台服务对多台机器

作为一个开发者,我以业务实现为主  上代码

springboot Netty搭建与使用 Java与机器通信_第1张图片

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 map = new HashMap();

    @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() {//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 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 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() {// 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();

    }



}

最后推荐一个测试Netty的工具  https://download.csdn.net/download/qq_34775102/11830134

 

如果你觉得这篇内容对你挺有启发请点赞+关注

你可能感兴趣的:(Java,Netty,spring,boot)