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

引入依赖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(9011).sync();//开启需要监听 的端口  
		        ChannelFuture future1 = b.bind(9012).sync();//开启需要监听 的端口 多开端口
		        if (future.isSuccess()) {
		            	System.out.println("启动 9011成功");
		        }
		        if (future1.isSuccess()) {
		        	System.out.println("启动 9012成功");
		    	}
		    }
		    
		    /**
		     * 销毁
		     */
		    @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)
		       //将当前的设备ip+端口存进map  当做下发设备的标识的key
		       //如果已经存在就不用重复存入map
		        if(map.get(url)==null){
		        		map.put(url, ctx);
		    	}
		        int users=0; 
		        //设备请求的 服务器端的地址   用作监听设备请求的那个端口  
		        String servicePort=ctx.channel().localAddress().toString();
		        //判断端口如果客户端请求的端口号为9011  
		         System.out.println("向:"+servicePort.substring(servicePort.length()-4, servicePort.length())+" 端口写入数据");
		        if(servicePort.substring(servicePort.length()-4, servicePort.length()).equals("9011")){
				        	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地址 +9011(个人开的9011端口 )就可以发送数据并写入数据库了

接下来是服务端向设备发送指令

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;

@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(url)地址  实现下发
		     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中的请求地址 然后客户端会打印接收到的数据

在这里插入图片描述
*结束、 有疑问请留言 **
**注:仅作参考 **

参考资源链接:[SpringBootNetty物联网温度采集中的应用](https://wenku.csdn.net/doc/43efozowjd?utm_source=wenku_answer2doc_content) 在设计基于SpringBootNetty物联网温度采集系统时,首先要理解Netty框架在处理网络I/O操作方面的优势,以及SpringBoot如何简化应用发和生命周期管理。根据《SpringBootNetty物联网温度采集中的应用》资源,你可以通过以下步骤实现所需的系统: 1. 设计系统架构:确定系统需要支持的通信协议(例如TCP/IP或串口通信),并根据物联网设备的硬件接口设计数据格式和传输协议。 2. 集成Netty:在SpringBoot项目中引入Netty依赖,并创建Netty服务器端处理器来监听指定端口接收来自物联网设备的温度数据Netty的异步事件驱动模型有助于处理大量并发连接,并确保高效的数据传输。 3. 数据处理:在Netty的ChannelHandler中实现数据格式化、解析和校验的逻辑。确保接收到的数据符合预期格式,并处理可能的异常和错误。 4. 温度数据采集:与物联网设备建立连接,使用适当的通信协议读取温度传感器数据。在接收数据后,通过Netty通道将数据转发到SpringBoot管理的业务逻辑中。 5. 集成SpringBoot:使用SpringBoot的自动配置和依赖注入功能,将Netty服务器与SpringBoot应用无缝集成。确保SpringBoot能够管理Netty服务器的生命周期,并提供必要的服务接口。 6. 数据存储与监控:实现数据持久化逻辑,将处理后的温度数据保存到数据库中。同时,集成实时监控模块,以便用户可以实时查看和分析采集到的温度数据。 通过上述步骤,你可以构建一个基于SpringBootNetty物联网温度采集系统,实现数据的实时采集、高效传输和有效监控。为了更深入理解整个实现过程,建议阅读《SpringBootNetty物联网温度采集中的应用》,该资源将为你提供详细的指导和深入的技术细节。 参考资源链接:[SpringBootNetty物联网温度采集中的应用](https://wenku.csdn.net/doc/43efozowjd?utm_source=wenku_answer2doc_content)
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值