Springboot+Netty实现基于天翼物联网平台CTWing(AIOT)终端TCP协议(透传模式)-设备终端(南向设备)

news2024/11/16 23:59:33

电信的天翼物联网平台CTWing(AIOT)原先是我们俗称的aep,主要用于接入nb-iot设备,当然也可以接入其他的设备,在熟悉AIOT平台后,做后端的我有时候急需终端样品(智能门禁,支付识别终端,CPE终端,考勤机等)做北向订阅的应用开发,可南向设备的开发需要一段时间,因此可以使用其他办法,工具啥的模拟终端设备进行数据交互的开发。

对于实时性要求高的设备,比如智能门禁机,当触发需要开门的请求后,需要立即给设备发送开门指令(信号),那么常用的tcp协议成为最好最简单快捷的一种选择方式。

对于天翼物联网平台的基础使用(注册,登录,创建产品)就不记录了,直接创建产品

要求:设备直连  TCP协议  明文  特征字符串 一型一密 透传 分类可选择智慧社区的配件

 

在这里我们首先获取到产品ID和Master-APIkey,在点击详情里面

产品ID:15506850

Master-APIkey:d894a1c38274440986dd4f4cc3a7799a

特征串:IicRLZ58eW_4LYp5EUIKdJcqyL5DU7XuepoQaV4U-SY

一般设备最长使用imei作为唯一的标识来进行通讯的,这里我模拟一个imei号码注册,拿到该设备的认证信息

869401041201815

 

这里有一个点,设备ID是产品ID+设备编号(imei)拼接而成

deviceId: 15506850869401041201815

 这些参数在终端程序中是需要使用到的,因此先行拿出来放着

在看AIOT平台对于TCP的协议,透传模式和非透传模式

tcp数据协议的地址(官网可找)接口介绍-中国电信天翼物联网CTWing门户网站

上图是协议的关键,至于协议的业务交互流程,AIOT有文档里已经给出了,还有示例,因此直接上使用Springboot+Netty模拟此协议的代码

新建Springboot的maven项目,pom.xml文件导入依赖包(用到了swagger来测试终端上报数据)

	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.5.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<groupId>boot.ctwing.tcp.terminal</groupId>
	<artifactId>boot-example-ctwing-tcp-terminal-2.0.5</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>boot-example-ctwing-tcp-terminal-2.0.5</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>io.netty</groupId>
			<artifactId>netty-all</artifactId>
			<version>4.1.29.Final</version>
		</dependency>

		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger2</artifactId>
			<version>2.9.2</version>
		</dependency>
		<dependency>
			<groupId>com.github.xiaoymin</groupId>
			<artifactId>swagger-bootstrap-ui</artifactId>
			<version>1.9.2</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<!-- 打包成一个可执行jar -->
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<executions>
					<execution>
						<goals>
							<goal>repackage</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>

Springboot启动类,Netty启动

package boot.ctwing.tcp.terminal;

import boot.ctwing.tcp.terminal.config.CtWingConstant;
import boot.ctwing.tcp.terminal.netty.TcpClient;
import boot.ctwing.tcp.terminal.utils.CtWingUtils;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

/**
 *  蚂蚁舞
 */
@SpringBootApplication
@EnableScheduling
public class BootCtWingTcpTerminal implements CommandLineRunner {
    public static void main( String[] args ) throws Exception {
    	SpringApplication.run(BootCtWingTcpTerminal.class, args);
        System.out.println( "Hello World!" );
    }

    @Override
    public void run(String... args) throws Exception {

        byte[] bytes = CtWingUtils.tcp_01_auth();
        new TcpClient().startup(CtWingConstant.port, CtWingConstant.address, bytes);

//        int port = 8996;
//        new IotTcpClient().connect(port, "127.0.0.1");
    }


}
SwaggerConfig配置
package boot.ctwing.tcp.terminal.config;

import com.google.common.base.Predicates;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 *  蚂蚁舞
 */
@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket createRestApi(){
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
                .apis(RequestHandlerSelectors.any()).paths(PathSelectors.any())
                .paths(Predicates.not(PathSelectors.regex("/error.*")))
                .paths(PathSelectors.regex("/.*"))
                .build().apiInfo(apiInfo());
    }

    private ApiInfo apiInfo(){
        return new ApiInfoBuilder()
                .title("天翼物联网CtWing终端模拟mock")
                .description("终端模拟需要的测试接口")
                .version("0.01")
                .build();
    }

    /**
     * http://localhost:8177/doc.html  地址和端口根据实际项目查看
     */


}

CtWingConstant静态类,里面包括产品Id,特征字符串和设备imei

package boot.ctwing.tcp.terminal.config;

/**
 *  蚂蚁舞
 */
public class CtWingConstant {

    //  产品ID
    public static final String productId = "15506850";

    //  设备imei
    public static final String imei = "869401041201815";

    //  特征字符串
    public static final String password = "IicRLZ58eW_4LYp5EUIKdJcqyL5DU7XuepoQaV4U-SY";

    public static final String version = "1.0";

    public static final String address = "tcp.ctwing.cn";
    public static final int port = 8996;

    //  登录认证
    public static final String tcp_hex_01 = "01";

    //  上行数据报文
    public static final String tcp_hex_02 = "02";

    //  下行数据报文
    public static final String tcp_hex_03 = "03";

    //  上行心跳
    public static final String tcp_hex_04 = "04";

    //  登录响应
    public static final String tcp_hex_05 = "05";

    //  心跳响应
    public static final String tcp_hex_06 = "06";


}
TcpClient
package boot.ctwing.tcp.terminal.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *  蚂蚁舞
 */
public class TcpClient {

    private final Logger log =  LoggerFactory.getLogger(this.getClass());

    public static SocketChannel socketChannel = null;

    private static final EventLoopGroup group = new NioEventLoopGroup();

    public void startup(int port, String host, byte[] bytes) throws Exception{

        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group);
            bootstrap.channel(NioSocketChannel.class);
            bootstrap.option(ChannelOption.TCP_NODELAY, true);
            bootstrap.handler(new TcpChannelInitializer<SocketChannel>());
            ChannelFuture f = bootstrap.connect(host, port).sync();
            if (f.isSuccess()) {
                socketChannel = (SocketChannel) f.channel();
                log.info("connect server success");
                f.channel().writeAndFlush(Unpooled.buffer().writeBytes(bytes));
                log.info("send success");
                f.channel().closeFuture().sync();
            }
        } catch (Exception e) {
            System.out.println(e.toString());
        } finally {
            group.shutdownGracefully();
        }
    }


}
TcpChannelInitializer<SocketChannel>
package boot.ctwing.tcp.terminal.netty;


import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;

/**
 *  蚂蚁舞
 * @param <SocketChannel>
 */
public class TcpChannelInitializer<SocketChannel> extends ChannelInitializer<Channel>{


    @Override
    protected void initChannel(Channel ch) throws Exception {
        //  二者选择一个就可以
        //  使用netty自带的
//        ch.pipeline().addLast("decoder", new ByteArrayDecoder());
//        ch.pipeline().addLast("encoder", new ByteArrayEncoder());

        // 使用自定义的
        ch.pipeline().addLast(new TcpMessageCodec());


        ch.pipeline().addLast(new TcpChannelInboundHandlerAdapter());

    }

}
TcpChannelInboundHandlerAdapter
package boot.ctwing.tcp.terminal.netty;


import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;

import java.util.List;

/**
 *  蚂蚁舞
 */
@ChannelHandler.Sharable
public class TcpMessageCodec extends MessageToMessageCodec<ByteBuf, ByteBuf> {


    @Override
    protected void encode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
        byte[] array = new byte[msg.readableBytes()];
        msg.getBytes(0, array);
        out.add(Unpooled.wrappedBuffer(array));
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
        byte[] array = new byte[msg.readableBytes()];
        msg.getBytes(0, array);
        out.add(array);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        System.out.println("OutIn异常!"+cause);
    }

}

TcpMessageCodec
package boot.ctwing.tcp.terminal.netty;


import boot.ctwing.tcp.terminal.config.CtWingConstant;
import boot.ctwing.tcp.terminal.utils.CtWingUtils;
import io.netty.buffer.Unpooled;
import io.netty.channel.socket.SocketChannel;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

/**
 *  蚂蚁舞
 */
@Service
public class TcpHeartTimer {

    //  使用定时器发送心跳
    @Scheduled(cron = "0 0/3 * * * ?")
    public void tcp_ct_wing_heart_timer() {
        String back = CtWingConstant.tcp_hex_04;
        byte[] data = CtWingUtils.hexStrToBytes(back);
        SocketChannel socketChannel = TcpClient.socketChannel;
        if( socketChannel != null && socketChannel.isOpen()) {
            socketChannel.writeAndFlush(Unpooled.buffer().writeBytes(data));
        }
    }

}
CtWingUtils
package boot.ctwing.tcp.terminal.utils;


import boot.ctwing.tcp.terminal.config.CtWingConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;

/**
 *  蚂蚁舞
 */
public class CtWingUtils {

    private static final Logger log =  LoggerFactory.getLogger(CtWingUtils.class);

    private static final char[] HEXES = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    public static String bytesToHexStr(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        StringBuilder hex = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) {
            hex.append(HEXES[(b >> 4) & 0x0F]);
            hex.append(HEXES[b & 0x0F]);
        }
        return hex.toString().toUpperCase();
    }

    public static byte[] hexStrToBytes(String hex) {
        if (hex == null || hex.length() == 0) {
            return null;
        }
        char[] hexChars = hex.toCharArray();
        byte[] bytes = new byte[hexChars.length / 2];   // 如果 hex 中的字符不是偶数个, 则忽略最后一个
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = (byte) Integer.parseInt("" + hexChars[i * 2] + hexChars[i * 2 + 1], 16);
        }
        return bytes;
    }

    public static String strToHexStr(String str) {
        StringBuilder sb = new StringBuilder();
        byte[] bs = str.getBytes();
        int bit;
        for (int i = 0; i < bs.length; i++) {
            bit = (bs[i] & 0x0f0) >> 4;
            sb.append(HEXES[bit]);
            bit = bs[i] & 0x0f;
            sb.append(HEXES[bit]);
        }
        return sb.toString().trim();
    }

    public static String hexStrToStr(String hexStr) {
        //能被16整除,肯定可以被2整除
        byte[] array = new byte[hexStr.length() / 2];
        try {
            for (int i = 0; i < array.length; i++) {
                array[i] = (byte) (0xff & Integer.parseInt(hexStr.substring(i * 2, i * 2 + 2), 16));
            }
            hexStr = new String(array, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
        return hexStr;
    }

    public static String hexLen4Calc(int fixed, int len){
       StringBuilder x = new StringBuilder(Integer.toHexString(len));
       int xC = fixed - x.length();
       for(int i = 0; i< xC; i++){
           x.insert(0, "0");
       }
       return x.toString();
    }

    public static byte[] tcp_01_auth(){
        String deviceId = CtWingConstant.productId+CtWingConstant.imei;
        String deviceIdLenHex = hexLen4Calc(4, deviceId.length());
        String deviceIdHex = strToHexStr(deviceId);
        String passwordLenHex = hexLen4Calc(4, CtWingConstant.password.length());
        String passwordHex = strToHexStr(CtWingConstant.password);
        String versionLenHex = hexLen4Calc(4, CtWingConstant.version.length());
        String versionHex = strToHexStr(CtWingConstant.version);

        String cmd = CtWingConstant.tcp_hex_01+deviceIdLenHex+deviceIdHex+passwordLenHex+passwordHex+versionLenHex+versionHex;
        log.info(cmd);
        return hexStrToBytes(cmd);
    }

    public static byte[] tcp_02_up_msg(String str){
        String upHexStr = strToHexStr(str);
        String upHexStrLenHex = hexLen4Calc(4, upHexStr.length()/2);
        String cmd = CtWingConstant.tcp_hex_02+upHexStrLenHex+upHexStr;
        log.info(cmd);
        return hexStrToBytes(cmd);
    }



}
TcpTerminalController
package boot.ctwing.tcp.terminal.controller;

import boot.ctwing.tcp.terminal.netty.TcpClient;
import boot.ctwing.tcp.terminal.utils.CtWingUtils;
import io.netty.buffer.Unpooled;
import io.netty.channel.socket.SocketChannel;
import org.springframework.web.bind.annotation.*;

@RestController
public class TcpTerminalController {

	@GetMapping(value = {"", "/"})
	public String index() {
		return "天翼物联网CtWing终端模拟mock";
	}

	@GetMapping("/reportData")
	public String reportData(@RequestParam(name="content",defaultValue="hello-myw-terminal") String content) {
		byte[] data = CtWingUtils.tcp_02_up_msg(content);
		SocketChannel socketChannel = TcpClient.socketChannel;
		if( socketChannel != null && socketChannel.isOpen()) {
			socketChannel.writeAndFlush(Unpooled.buffer().writeBytes(data));
		}
		return "success";
	}

}

代码目录结构

boot-example-ctwing-tcp-terminal-2.0.5
    │  pom.xml
    │  
    └─src
        ├─main
        │  ├─java
        │  │  └─boot
        │  │      └─ctwing
        │  │          └─tcp
        │  │              └─terminal
        │  │                  │  BootCtWingTcpTerminal.java
        │  │                  │  
        │  │                  ├─config
        │  │                  │      CtWingConstant.java
        │  │                  │      SwaggerConfig.java
        │  │                  │      
        │  │                  ├─controller
        │  │                  │      TcpTerminalController.java
        │  │                  │      
        │  │                  ├─netty
        │  │                  │      TcpChannelInboundHandlerAdapter.java
        │  │                  │      TcpChannelInitializer.java
        │  │                  │      TcpClient.java
        │  │                  │      TcpHeartTimer.java
        │  │                  │      TcpMessageCodec.java
        │  │                  │      
        │  │                  └─utils
        │  │                          CtWingUtils.java
        │  │                          
        │  └─resources
        │          application.properties
        │          logback-spring.xml
        │          
        └─test
            └─java
                └─boot
                    └─ctwing
                        └─tcp
                            └─terminal
                                    BootCtWingTcpTerminalTest.java
                                    

启动Springboot项目后可以看到最后的日志信息是这样的

20:31:55.987 spring-boot-logging [main] INFO  o.a.tomcat.util.net.NioSelectorPool - Using a shared selector for servlet write/read
20:31:56.014 spring-boot-logging [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8177 (http) with context path ''
20:31:56.022 spring-boot-logging [main] INFO  b.c.t.terminal.BootCtWingTcpTerminal - Started BootCtWingTcpTerminal in 7.813 seconds (JVM running for 8.702)
20:31:56.027 spring-boot-logging [main] INFO  b.c.tcp.terminal.utils.CtWingUtils - 0100173135353036383530383639343031303431323031383135002b496963524c5a353865575f344c5970354555494b644a6371794c35445537587565706f51615634552d53590003312e30
channelActive
20:31:58.379 spring-boot-logging [main] INFO  b.c.tcp.terminal.netty.TcpClient - connect server success
20:31:58.413 spring-boot-logging [main] INFO  b.c.tcp.terminal.netty.TcpClient - send success
20:31:58.542 spring-boot-logging [nioEventLoopGroup-2-1] INFO  b.c.t.t.n.TcpChannelInboundHandlerAdapter - data--050000
channelReadComplete

启动就开始认证

0100173135353036383530383639343031303431323031383135002b496963524c5a353865575f344c5970354555494b644a6371794c35445537587565706f51615634552d53590003312e30

得到服务端的响应信息

050000

心跳返回是(定时器3分钟发一次(04),平台说的是5分钟内)

06

此时我们再看AIOT平台的设备管理详情里面

 显示已经激活了

认证成功  心跳也正常 那么开始发送数据,一般发送的数据在设备端是不含中文的,我这里把中文也带上,测试下发送中文是否可用可行,我的端口是8177 因此本地访问

http://localhost:8177/doc.html

 我发送了好几条数据(字符串形式),回到AIOT平台的数据里查看

如此模拟设备的数据成功上传到天翼物联网平台AIOT

6JqC6JqB6Iie


6JqC6JqB5Lmf5Lya6Lez6Iie


bXl3


bXl5aHR3MTIzNDU0NjU0Njc0ZXF3amRjcW93ZWljcW93aXhjbmRjeA==

 四条数据是经过base64的,因此需要解开,在转成我发送的字符串就可以

package boot.ctwing.tcp.app;

import boot.ctwing.tcp.app.utils.CtWingUtils;
import java.util.Base64;

public class Test {

    public static void main(String[] args) {
        byte[] decoded1 = Base64.getDecoder().decode("6JqC6JqB6Iie");
        String hex1 = CtWingUtils.bytesToHexStr(decoded1);
        System.out.println(CtWingUtils.hexStrToStr(hex1));

        byte[] decoded2 = Base64.getDecoder().decode("bXl3");
        String hex2 = CtWingUtils.bytesToHexStr(decoded2);
        System.out.println(CtWingUtils.hexStrToStr(hex2));

        byte[] decoded3 = Base64.getDecoder().decode("6JqC6JqB5Lmf5Lya6Lez6Iie");
        String hex3 = CtWingUtils.bytesToHexStr(decoded3);
        System.out.println(CtWingUtils.hexStrToStr(hex3));

        byte[] decoded4 = Base64.getDecoder().decode("bXl5aHR3MTIzNDU0NjU0Njc0ZXF3amRjcW93ZWljcW93aXhjbmRjeA==");
        String hex4 = CtWingUtils.bytesToHexStr(decoded4);
        System.out.println(CtWingUtils.hexStrToStr(hex4));
    }
}

最终得到的字符串数据

蚂蚁舞
myw
蚂蚁也会跳舞
myyhtw123454654674eqwjdcqoweicqowixcndcx

如此使用springboot+netty模拟天翼物联网CtWing的终端设备算是完成了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/113669.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用 Swift/SwiftUI 的音频可视化

IOS 应用程序中的音频可视化是一项流行的功能,在实现聊天功能时可能需要它。将它添加到我最近的项目之一时,我个人遇到了一些问题。 你们中的一些人可能在开发包含聊天功能的应用程序时遇到过问题,其中某些消息可能包含音频。这些消息需要在应用程序内进行适当的音频可视化,…

【算法题解】3. 颠倒二进制位

文章目录题目解法一解题思路代码实现复杂度分析解法二解题思路代码实现复杂度分析解法三解题思路代码实现复杂度分析题目 颠倒给定的 32 位无符号整数的二进制位。来自&#xff1a;leetcode 解法一 解题思路 取 n 的最低位&#xff0c;赋值给 ans 的最低位&#xff08;ans 初…

mybatis 多对一查询的处理方式,1.按照查询嵌套处理(子查询),2、按照结果嵌套处理(连表查询)

多对一查询 1、实体类 Student实体类&#xff1a; public class Student { private int id; private String name; private Teacher teacher;//对象属性}Teacheer 实体类&#xff1a; public class Teacher { private int id; private String name;2、Mybatis配置文件mybatis…

FastDDS(4)安装步骤

eProsima Fast DDS for Linux的最新二进制安装版本可在eProssma网站找到。 eProsima Fast DDSSpecialized on high performance middleware. Check out our comparatives such as Apache Thrift vs Protocol Buffers vs Fast Buffers or ZMQ vs Fast RTPS.https://www.eprosim…

从一道经典题来弄懂Eventloop(搞不懂算我输)

前言 时间不知不觉来到了11月底&#xff0c;马上也要准备一下寒假的实习了。 最近打算把面试中的一些拦路虎给解决掉&#xff01;&#xff01; 先拿臭名昭著的Eventloop开刀~ 经典题 async function foo() {console.log(foo) } async function bar() {console.log(bar start…

RabbitMQ:基本消息模型

单生产单消费模型&#xff0c;即基本消息模型或简单消费模型&#xff0c;即完成基本的一对一消息转发。 RabbitMQ 单生产单消费模型主要有以下三个角色构成&#xff1a; 生产者&#xff08;producer/ publisher&#xff09;&#xff1a;一个发送消息的用户应用程序。消费者&…

JS面试题--JavaScript数据类型

数据类型 1.JavaScript有哪些数据类型&#xff0c;它们的区别&#xff1f; JavaScript共有八种数据类型&#xff0c;分别是 Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt。 其中 Symbol 和 BigInt 是ES6 中新增的数据类型&#xff1a; ● Symbol 代表…

Linux系统基础——程序和进程

代码&#xff0c;程序&#xff0c;进程 特此说明: 刘超的趣谈linux操作系统是比较重要的参考资料&#xff0c;本文大部分内容和图片来源于这个专栏。 1 实验环境 运行一个demo&#xff0c;主要功能是主进程通过系统调用fork一个新的进程&#xff0c;子进程功能是加载二进制文件…

背包模型~

背包模型 概述 ​ 最长上升子序列&#xff1a;序列DP&#xff08;相邻两个被选择的有关系&#xff09; 背包问题&#xff1a;组合DP&#xff0c;在全局的考虑之下最小 f[i][j]&#xff1a;i 表示搞了多少&#xff0c;j 表示限制 集合&#xff1a;所有仅仅从前 i 个物品当…

论文推荐:CCNet用于语义分割的交叉注意力

CCNet&#xff0c; Transformer递归交叉自注意力&#xff0c;比非局部神经网络更有效。华中科技大学、地平线、ReLER 和伊利诺伊大学香槟分校联合研发 论文提出了交叉网络 (CCNet)&#xff0c;对于每个像素&#xff0c;CCNet 中的一个新的交叉注意力模块收集其交叉路径上所有像…

智慧路口:未来都市的智能节点

摘要交通路口是部署未来智慧城市的计算、通信和情报服务的最合适地点。需要收集和处理的大量数据&#xff0c;再加上隐私和安全问题&#xff0c;促使边缘计算范式的使用&#xff0c;这种范式与大都市的物理交叉路口很好地吻合。本文主要针对高带宽、低时延的应用&#xff0c;在…

2007-2022年消费者信心、满意度、预期指数月度数据(CCI、CEI、CSI、CGPI)

根据企业商品价格指数与消费者信心指数、消费者满意指数、消费者预期指数的月度数据&#xff0c;可以探究商品价格对消费者信心的影响作用和作用机制。 商品价格与消费者信心的三类细分指数均具有滞后二阶关联&#xff0c;其中&#xff0c;商品价格对对消费者预期指数的影响作…

IndexedDB的包装器JsStore - 实现登录功能及事务处理

JsStore是IndexedDB的包装器。它提供了简单的SQL像api&#xff0c;这是容易学习和使用。 IndexedDb查询可以在web worker内部执行&#xff0c;JsStore通过提供一个单独的worker文件来保持这种功能。 最近有位叫Pioneer网友一直在问我关于事务的实现方式&#xff0c;关于…

谷粒学院——Day13【微信扫描登录】

OAuth2 OAuth2的使用场景 一、OAuth2解决什么问题 1. OAuth2提出的背景 照片拥有者想要在云冲印服务上打印照片&#xff0c;云冲印服务需要访问云存储服务上的资源。 2. 图例 资源拥有者&#xff1a;照片拥有者。 客户应用&#xff1a;云冲印。 受保护的资源&#xff…

Python pandas库|任凭弱水三千,我只取一瓢饮(2)

上一篇链接&#xff1a; Python pandas库&#xff5c;任凭弱水三千&#xff0c;我只取一瓢饮&#xff08;2&#xff09;_Hann Yang的博客-CSDN博客 I~Q&#xff1a; Function10~25 Types[Function][9:25] [infer_freq, interval_range, isna, isnull, json_normalize, lres…

④【Maven】Maven的构建命令

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ Maven的构建命令一、注意二、&#x1f680;清理…

指针与数组的联系与区别【一万六千字超详解】

&#x1f3d6;️作者&#xff1a;malloc不出对象 ⛺专栏&#xff1a;《初识C语言》 &#x1f466;个人简介&#xff1a;一名双非本科院校大二在读的科班编程菜鸟&#xff0c;努力编程只为赶上各位大佬的步伐&#x1f648;&#x1f648; 目录前言数组的性质1.1 数组的内存布局1…

第四章 Spring的基础用法

文章目录 Spring的起源和背景理解依赖注入Spring容器理解Spring容器中的Bean管理容器中的Bean及其依赖注入自动装配使用Java类进行配置管理使用静态工厂、实例工厂创建Bean实例抽象Bean与子Bean容器中的工厂Bean管理Bean的生命周期几种特殊的依赖注入Spring的简化配置SpEL的功…

kali中间人攻击

数据来源 一、中间人攻击原理 1. 利用的ARP协议的漏洞 2. ARP协议原理&#xff1a; 1&#xff09;发送ARP广播请求目标MAC地址 2&#xff09;目标主机发送ARP单播应答&#xff0c;响应MAC地址 3. ARP攻击原理 攻击人通过发送虚假的ARP应答实现ARP缓存投毒!而受害人没有办法进行…

文件存储案例

1.文件存储-File文件存储案例 1.1.案例要求 1.2参考代码 文件读取 百度安全验证 文件最终的保存的目录在/data/data/user/0/包/files下&#xff08;1&#xff09;布局文件 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android&q…