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