springboot集成netty实现物联网设备数据接收、控制、下发、多开监听端口、区分端口



原创 叫我长安吧 最后发布于2019-08-12 14:26:13 阅读数 2349 收藏
展开

引入依赖jar

        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.32.Final</version>
        </dependency>
        <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-configuration-processor</artifactId>
           <optional>true</optional>
        </dependency>

  

直接上代码
开启要监听的端口

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

import org.springframework.stereotype.Component;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
//物联网 开启检测 并写入数据库
@Component
public class NettyStart {
            @Resource
            private ServerHandler serverHandler;
            private EventLoopGroup bossGroup = new NioEventLoopGroup();
            private EventLoopGroup workGroup = new NioEventLoopGroup();
            
            /**
             * 启动netty服务
             * @throws InterruptedException
             */
            @PostConstruct
            public void start() throws InterruptedException {
                ServerBootstrap b=new ServerBootstrap();
                b.group(bossGroup,workGroup)
                        .channel(NioServerSocketChannel.class)
                        .option(ChannelOption.SO_BACKLOG,128)
                        .childHandler(new ChannelInitializer<SocketChannel>()  {
                            @Override
                            protected void initChannel(SocketChannel socketChannel) throws Exception {
                                socketChannel.pipeline().addLast(serverHandler);
                            }
                        });
                ChannelFuture future = b.bind(9898).sync();//开启需要监听 的端口  
                ChannelFuture future1 = b.bind(9899).sync();//开启需要监听 的端口 多开端口
                if (future.isSuccess()) {
                        System.out.println("启动 9898 成功");
                }
                if (future1.isSuccess()) {
                    System.out.println("启动 9899 成功");
            }
                
            }
            
            /**
             * 销毁
             */
            @PreDestroy
            public void destroy() {
                bossGroup.shutdownGracefully().syncUninterruptibly();
                workGroup.shutdownGracefully().syncUninterruptibly();
                System.out.println("关闭 Netty 成功");
            }
}

  

实现类

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.stereotype.Component;

import com.yun.Util.TimeUtile;
import com.yun.admin.entity.Product_data;
import com.yun.admin.service.impl.Product_dataServiceImpl;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
import net.sf.json.JSONObject;

//物联网 开启检测端口 并写入数据库
@Component
@Sharable
public class ServerHandler extends ChannelInboundHandlerAdapter {
            //此处注入数据源操作sql   执行插入设备上传的数据
            @Resource
            private Product_dataServiceImpl product_dataServiceImpl;
            //  将当前客户端连接 存入map   实现控制设备下发 参数
            public  static Map<String, ChannelHandlerContext> map = new HashMap<String, ChannelHandlerContext>();
           
            /**
             * 获取数据
             * @param ctx 上下文
             * @param msg 获取的数据
             * @throws UnsupportedEncodingException
             */
            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) throws UnsupportedEncodingException{
                //msg为接收到的客户端传递的数据   个人这边直接传的json 数据
                ByteBuf readMessage= (ByteBuf) msg;
                //解析客户端json 数据
                JSONObject json=JSONObject.fromObject(readMessage.toString(CharsetUtil.UTF_8));
                System.out.println("接收到的数据"+readMessage.toString(CharsetUtil.UTF_8));
                
                //获取客户端的请求地址  取到的值为客户端的 ip+端口号
                String url=ctx.channel().remoteAddress().toString();//设备请求地址(个人将设备的请求地址当作 map 的key)
               
                if(map.get(url)!=null){//如果不为空就不存
                        
                }else{//否则就将当前的设备ip+端口存进map  当做下发设备的标识的key
                    map.put(url, ctx);
                }
                int users=0;
                //设备请求的 服务器端的地址   用作监听设备请求的那个端口  
                String servicePort=ctx.channel().localAddress().toString();
                //判断端口如果客户端请求的端口号为9898   就是写入第一张表   这样可以实现 设备传递数据参数不一致
                 System.out.println("向:"+servicePort.substring(servicePort.length()-4, servicePort.length())+" 端口写入数据");
                if(servicePort.substring(servicePort.length()-4, servicePort.length()).equals("9898")){
                            Product_data product_data=new Product_data();
                            //设备请求地址  存入数据库  下方controller层 通过设备id查询此地址   取到map种存入的 ChannelHandlerContext 实现数据下发
                            product_data.setUrl(url);
                            product_data.setJson(readMessage.toString(CharsetUtil.UTF_8));//设备请求时原生数据  
                            product_data.setDeviceID(json.get("deviceID").toString());//设备数据1
                            product_data.setPower1(json.get("power1").toString());//设备数据2
                            product_data.setPower2(json.get("power2").toString());//设备数据3
                            product_data.setPower3(json.get("power3").toString());//设备数据4
                            product_data.setAcquisitionTime(TimeUtile.showDate());//时间 (个人整的当前时间工具类  替换成自己获取当前时间的方法即可)
                            //执行写入操作    此处写你们要插入的表操作语句即可
                            users = product_dataServiceImpl.add_Device_shuju(product_data);
                 }else{
                             //否则取另外的值 进行写入 数据库
                             Product_data product_data=new Product_data();
                             //设备请求地址  存入数据库  下方controller层 通过设备id查询此地址   取到map种存入的 ChannelHandlerContext 实现数据下发
                            product_data.setUrl(url);
                            product_data.setJson(readMessage.toString(CharsetUtil.UTF_8));//设备请求时原生数据  
                            product_data.setDeviceID(json.get("deviceID").toString());//设备数据1
                            product_data.setData1(json.get("data1").toString());//设备数据2
                            product_data.setData2(json.get("data2").toString());//设备数据3
                            product_data.setData3(json.get("data3").toString());//设备数据4
                            product_data.setAcquisitionTime(TimeUtile.showDate());//时间 (个人整的当前时间工具类  替换成自己获取当前时间的方法即可)
                            //执行写入操作    此处写你们要插入的表操作语句即可
                            users = product_dataServiceImpl.add_Device_data(product_data);
                 }
                String rmsg;
                if(users>0){
                        rmsg="11 02 00 C4 00 16 ";//返回成功的信息
                 }else{
                         rmsg="0";//返回失败的信息
                 }
                ByteBuf message= Unpooled.copiedBuffer(rmsg.getBytes());//处理返回的信息
                   //ctx.write(in2);//返回信息
                ctx.writeAndFlush(message);//返回信息
                    //刷新缓存区
                   ctx.flush();
            }
            
            @Override
            public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                    cause.printStackTrace();
                    ctx.close();
            }
}


至此就可以实现 服务器端接受设备传递的数据了 ,服务端 可以根据 当前电脑ip地址 +9898(个人开的9898端口 )就可以发送数据了
**控制设备 **

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.yun.Util.Result;
import com.yun.Utile.SheBei.ServerHandler;
import com.yun.admin.entity.Product_data;
import com.yun.admin.service.impl.Product_dataServiceImpl;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;

@Controller
@RequestMapping("/equipmenContro")
public class EquipmentController {
        
        @Autowired
        private Product_dataServiceImpl product_dataServiceImpl;
        
        @RequestMapping(value="/equipment",method=RequestMethod.POST)
        public @ResponseBody Result equipment(Product_data product_data){
             //入参 设备id   根据设备id  查询设备最后一次录入数据时候的 ip地址  实现下发
             Product_data product=product_dataServiceImpl.select_Product_data_url(product_data);
             if(product!=null){
                 //需要给设备发送的 16进制数据
                 String msg=" 16 27 88 90 12 45 31 15 41 ";
                 //转码
                 ByteBuf message= Unpooled.copiedBuffer(msg.getBytes());
                 //执行设备控制    根据product.getUrl() 上个类写入map  的key  取到map中的 ChannelHandlerContext  执行writeAndFlush发送数据
                 ServerHandler.map.get(product.getUrl()).channel().writeAndFlush(message);
                 return Result.toClient(1,"成功");
             }else{
                 return  Result.toClient(0,"失败");
             }
            
        }
}

 
**OK完成 附上效果图 **

1、 启动
在这里插入图片描述

 

 


2、客户端发起连接 并发送数据
在这里插入图片描述

 

 


3、服务端接到数据 打印
在这里插入图片描述

 

 


4、服务器向客户端发送数据 实现设备控制 直接调用最后controller中的请求地址 然后客户端会打印接收到的数据
在这里插入图片描述

 

 


**结束、 有疑问请留言 **

**注: 仅为个人开发时遇到的整合问题 仅作参考 **
————————————————
版权声明:本文为CSDN博主「叫我长安吧」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42754347/article/details/99297982


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM