MQTT研究之EMQ:【CoAP协议的ECC证书研究】
今天研究的内容,是CoAP这个协议在EMQ消息队列的支持,CoAP是一个受限资源的协议,基于UDP实现的多用于物联网环境的通信协议。相关介绍不多说,可以看RFC。
CoAP协议下,基于DTLS通信,同样因为协议的产生背景原因,所以,对秘钥大小有有一些要求,尽量的小,所以ECC(椭圆曲线)秘钥算法成为了首先,比RSA秘钥短很多,但是加密安全强度不比RSA对应较长的秘钥安全性低。所以,EC加密算法研究成为了本博文的重点,另外,CoAP的证书中签名算法,也是有所限制的,用的是ECDSA,因为签名算法和秘钥加密算法是对应着工作的。
相关验证逻辑,可以基于CoAP的开发工具Californium的java三件套(core,connector,scandium),可以用证书进行验证。
《一》. 下面看看基于OpenSSL工具创建EC证书的过程
[root@tkwh-kfcs-app2 coaps]# openssl ecparam -out coapCA.key -name secp521r1 -genkey
[root@tkwh-kfcs-app2 coaps]# openssl req -new -key coapCA.key -out coapCA.csr
[root@tkwh-kfcs-app2 coaps]# openssl x509 -req -days -in coapCA.csr -signkey coapCA.key -out coapCA.crt [root@tkwh-kfcs-app2 coaps]# openssl ecparam -out coapApp.key -name secp521r1 -genkey
[root@tkwh-kfcs-app2 coaps]# openssl req -new -key coapApp.key -out coapApp.csr
[root@tkwh-kfcs-app2 coaps]# openssl x509 -req -days -in coapApp.csr -signkey coapApp.key -out coapApp.crt
从这个指令过程看,证书创建的步骤,EC算法和RSA算法没有什么太大的区别,也是三步走(1. 自签名根证书,2.生成CSR证书签名请求,3.生成对应目标证书)
《二》下面基于JAVA原生JDK的工具创建ECC的证书全流程进行分享,直接上相关的代码,希望能给到相关朋友一些帮助,有什么不清楚,可以参考我前面的博文,关于RSA证书的创建过程。
1.创建秘钥对
/**
* algo: e.g. ECC
* signAlgo: e.g. secp256r1
* @param algo
* @param signAlgo
* @return
*/
public static KeyPair getKeyPair(String algo, String signAlgo) {
KeyPairGenerator keyPairGenerator = null;
try {
keyPairGenerator = KeyPairGenerator.getInstance(algo);
ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec(signAlgo);
keyPairGenerator.initialize(ecGenParameterSpec, new SecureRandom());
KeyPair keyPair = keyPairGenerator.generateKeyPair();
return keyPair;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
return null;
}
2.创建自签名证书(CA)
/**
* 生成自签名证书
*
* @param publicKey 公钥对象
* @param privateKey 私钥对象
* @param subj 证书主体描述信息
* @param notBefore 有效期起始日期
* @param validDays 有效期长度
* @return
* @throws Exception
*/
public static X509Certificate createRootCert(PublicKey publicKey, PrivateKey privateKey, String subj, Date notBefore, long validDays) throws Exception{ String algo = "SHA256WITHECDSA";
try {
//证书拥有者subject的描述name
sun.security.x509.X500Name subject = new sun.security.x509.X500Name(subj); CertificateExtensions certExts = new CertificateExtensions();
certExts.set(SubjectKeyIdentifierExtension.NAME, new SubjectKeyIdentifierExtension((new KeyIdentifier(publicKey)).getIdentifier()));
certExts.set(AuthorityKeyIdentifierExtension.NAME, new AuthorityKeyIdentifierExtension(new KeyIdentifier(publicKey), null, null));
//设置是否根证书
BasicConstraintsExtension bce = new BasicConstraintsExtension(true, -);
certExts.set(BasicConstraintsExtension.NAME, new BasicConstraintsExtension(false, bce.getExtensionValue())); //配置证书的有效期,并生成根证书(自签名证书)
X509CertInfo x509CertInfo = new X509CertInfo();
//设置证书的版本号
x509CertInfo.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3)); AlgorithmId algorithmId = AlgorithmId.get(algo);
x509CertInfo.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algorithmId)); //设置证书的签发者信息
x509CertInfo.set(X509CertInfo.ISSUER, subject); //设置证书的拥有者信息
x509CertInfo.set(X509CertInfo.SUBJECT, subject); //设置证书的序列号,基于当前时间计算
x509CertInfo.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber((int) (System.currentTimeMillis() / 1000L))); //设置证书的公钥
x509CertInfo.set(X509CertInfo.KEY, new CertificateX509Key(publicKey)); //设置证书有效期
Date endDate = new Date(notBefore.getTime() + validDays * * * * 1000L);
CertificateValidity cv = new CertificateValidity(notBefore, endDate);
x509CertInfo.set(X509CertInfo.VALIDITY, cv); x509CertInfo.set(CertificateExtensions.NAME, certExts); X509CertImpl cert = new X509CertImpl(x509CertInfo);
try {
cert.sign(privateKey, algo);
} catch (InvalidKeyException | CertificateException | NoSuchAlgorithmException | NoSuchProviderException | SignatureException e3) {
e3.printStackTrace();
} return cert; } catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} return null;
}
3.创建用户证书(用2中的证书签发客户证书)
/**
* 基于根证书签发客户证书(非CA证书),即intermediate certificate
*
* @param ca 根证书文件对象
* @param caKey 根证书对应的私钥
* @param publicKey 待签发证书的公钥
* @param subj 待签发证书的主体描述信息
* @param notBefore 证书有效期起点
* @param validDays 证书有效期长度
* @param sginAlgo 证书签名算法
* @return
*/
public static X509Certificate createUserCert(X509Certificate ca, PrivateKey caKey, PublicKey publicKey, String subj, Date notBefore, long validDays, String sginAlgo) { //获取ca证书
X509Certificate caCert = ca; X509CertInfo x509CertInfo = new X509CertInfo(); try {
//设置证书的版本号
x509CertInfo.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3)); //设置证书的序列号,基于当前时间计算
x509CertInfo.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber((int) (System.currentTimeMillis() / 1000L))); /**
* 下面这个设置算法ID的代码,是错误的,会导致证书验证失败,但是报错不是很明确。 若将生成的证书存为keystore,让后keytool转换
* 会出现异常。
*
* 重点: AlgorithmId的参数设置要和后面的证书签名中用到的算法信息一致。
*/
AlgorithmId algorithmId = AlgorithmId.get(sginAlgo);
x509CertInfo.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algorithmId)); //设置证书的签发者信息
sun.security.x509.X500Name issuer = new sun.security.x509.X500Name(caCert.getIssuerX500Principal().toString());
x509CertInfo.set(X509CertInfo.ISSUER, issuer); //设置证书的拥有者信息
sun.security.x509.X500Name subject = new sun.security.x509.X500Name(subj);
x509CertInfo.set(X509CertInfo.SUBJECT, subject); //设置证书的公钥
x509CertInfo.set(X509CertInfo.KEY, new CertificateX509Key(publicKey)); //设置证书有效期
Date endDate = new Date(notBefore.getTime() + validDays * * * * 1000L);
CertificateValidity cv = new CertificateValidity(notBefore, endDate);
x509CertInfo.set(X509CertInfo.VALIDITY, cv); CertificateExtensions exts = new CertificateExtensions(); exts.set(SubjectKeyIdentifierExtension.NAME, new SubjectKeyIdentifierExtension((new KeyIdentifier(publicKey)).getIdentifier()));
exts.set(AuthorityKeyIdentifierExtension.NAME, new AuthorityKeyIdentifierExtension(new KeyIdentifier(ca.getPublicKey()), null, null));
exts.set(BasicConstraintsExtension.NAME, new BasicConstraintsExtension(false,false,-));
x509CertInfo.set(CertificateExtensions.NAME, exts); } catch (CertificateException cee) {
cee.printStackTrace();
} catch (IOException eio) {
eio.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} // 获取CA私钥
PrivateKey caPrivateKey = caKey;
//用CA的私钥给当前证书进行签名,获取最终的下游证书(证书链的下一节点)
X509CertImpl cert = new X509CertImpl(x509CertInfo);
try {
cert.sign(caPrivateKey, sginAlgo);
} catch (InvalidKeyException | CertificateException | NoSuchAlgorithmException | NoSuchProviderException | SignatureException e3) {
e3.printStackTrace();
}
return cert;
}
4. 证书的导出和导入相关方法
/**
* 导出ECC私钥文件存入文件,PEM格式,PKCS#8编码
* @param privateKey
* @param keyPath
* @throws Exception
*/
public static void savePrivateKeyAsPEM(PrivateKey privateKey, String keyPath) throws Exception {
String content = Base64Util.encode(privateKey.getEncoded());
File file = new File(keyPath);
try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw")) {
randomAccessFile.write(BEGIN_EC_PRIVATE_KEY.getBytes());
randomAccessFile.write(NEW_LINE.getBytes());
int i = ;
for (; i<(content.length() - (content.length() % )); i+=) {
randomAccessFile.write(content.substring(i, i + ).getBytes());
randomAccessFile.write(NEW_LINE.getBytes());
} randomAccessFile.write(content.substring(i).getBytes());
randomAccessFile.write(NEW_LINE.getBytes()); randomAccessFile.write(END_EC_PRIVATE_KEY.getBytes());
}
}
/**
* 导出ECC公钥文件存入文件,PEM格式,PKCS#8编码
*
* @param publicKey
* @param name
* @throws Exception
*/
public static void savePublicKeyAsPEM(PublicKey publicKey, String name) throws Exception {
String content = Base64Util.encode(publicKey.getEncoded());
File file = new File(name);
try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw")) {
randomAccessFile.write(BEGIN_EC_PUBLIC_KEY.getBytes());
randomAccessFile.write(NEW_LINE.getBytes());
int i = ;
for (; i<(content.length() - (content.length() % )); i+=) {
randomAccessFile.write(content.substring(i, i + ).getBytes());
randomAccessFile.write(NEW_LINE.getBytes());
} randomAccessFile.write(content.substring(i).getBytes());
randomAccessFile.write(NEW_LINE.getBytes()); randomAccessFile.write(END_EC_PUBLIC_KEY.getBytes());
}
}
这里需要说明的是,写入文件后,文件格式中的头部和尾部信息如下:
private static final String BEGIN_EC_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----";
private static final String END_EC_PRIVATE_KEY = "-----END PRIVATE KEY-----";
private static final String BEGIN_EC_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----";
private static final String END_EC_PUBLIC_KEY = "-----END PUBLIC KEY-----";
用OPENSSL创建的EC证书私钥,默认情况下会含有EC PARAMETERS的描述,这个部分,JAVA生成过程中,目前没有弄清楚,如何能做到和OPENSSL一样,不过,不考虑EC PARAMETERS部分,整个证书运行逻辑没有问题。(若有知道的博友,可以给我留言,告知我JAVA代码如何实现openssl生成的EC证书私钥模式的文件),下面给予一个对比,OPENSSL的EC私钥内容和用上述JAVA生成的EC私钥内容:
OPENSSL(PKCS#1编码):
openssl ecparam -out coapApp.key -name secp521r1 -genkey
-----BEGIN EC PARAMETERS-----
BgUrgQQAIw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MIHcAgEBBEIBHpCev79KIY4T9lMyheMD9A+kXUXxmhbTdQO+bA9PCeLeXpUuHiPU
dgJ31MjWYBe/5lr9Vr9kwZ20CAErIPDgttCgBwYFK4EEACOhgYkDgYYABAGhKHT6
J6aihJyNgjdGNDP2yaCGDZjmuQw2JIs9l0C27B6KHytxOV5qZfvA80s8kq/a1FBn
lUlHHjsEaVi20wWTmAFMgs75xAU+VjXEU9i03GaQuwC73mySAHWPWVQXmFu0b+Bz
wfvBf8so3Qew054UFbmg1zvcjZM0rBhn6GZtp7LOZw==
-----END EC PRIVATE KEY-----
查看具体内容:
[root@ws2 opt]# openssl ec -in coapApp.key -noout -text
read EC key
Private-Key: ( bit)
priv:
:1e::9e:bf:bf:4a::8e::f6::::e3:
:f4:0f:a4:5d::f1:9a::d3:::be:6c:0f:
4f::e2:de:5e::2e:1e::d4::::d4:c8:
d6:::bf:e6:5a:fd::bf::c1:9d:b4:::
2b::f0:e0:b6:d0
pub:
::a1:::fa::a6:a2::9c:8d::::
::f6:c9:a0::0d::e6:b9:0c:::8b:3d:
::b6:ec:1e:8a:1f:2b:::5e:6a::fb:c0:
f3:4b:3c::af:da:d4::::::1e:3b::
::b6:d3:::::4c::ce:f9:c4::3e:
::c4::d8:b4:dc:::bb::bb:de:6c::
::8f:::::5b:b4:6f:e0::c1:fb:c1:
7f:cb::dd::b0:d3:9e:::b9:a0:d7:3b:dc:
8d:::ac:::e8::6d:a7:b2:ce:
ASN1 OID: secp521r1
NIST CURVE: P-
JAVA(PKCS#8编码):
ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec(“secp256r1”);
-----BEGIN PRIVATE KEY-----
MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCAoWE90so3R0wAj/kWS
p43qZEHS2WcdZZAehpPtfZyV6A==
-----END PRIVATE KEY-----
查看具体内容:
[root@ws2 opt]# openssl ec -in eccDevCertPem.key -noout -text
read EC key
Private-Key: ( bit)
priv:
::4f::b2:8d:d1:d3:::fe:::a7:8d:
ea:::d2:d9::1d:::1e:::ed:7d:9c:
:e8
pub:
:af::c5:4f:::::0d:c7:0a:9d:::
f0:4c:ab:f1::5c:cf:::e8:9c:c7::b4::
b0:a9::2a:::2e::fe::dc:1c:8f:c9:cb:
fa:2f::6a:bb:c3::d2:3d::ad:d5:9c::f5:
1d:1e:9d::3b
ASN1 OID: prime256v1
NIST CURVE: P-
5. JAVA创建证书的DEMO
public void fromZeroToStart() throws Exception {
String subjCA = "OU=TaiKang,O=TKCloud,L=Wuhan,ST=Hubei,C=CN,CN=IOT_" + "ECC_CA";
String subjSVR = "OU=TaiKang,O=TKCloud,L=Wuhan,ST=Hubei,C=CN,CN=" + "10.95.197.8";
String subjDev = "OU=TaiKang,O=TKCloud,L=Wuhan,ST=Hubei,C=CN,CN=IOT_" + "Device"; KeyPair eccCaKey = CertUtils.getKeyPair("EC", "secp256r1");
KeyPair eccEmKey = CertUtils.getKeyPair("EC", "secp256r1");
KeyPair eccDvKey = CertUtils.getKeyPair("EC", "secp256r1"); //自签发根证书
Date notBefore = new Date();
X509Certificate crt = CertUtils.createRootCert(eccCaKey.getPublic(), eccCaKey.getPrivate(), subjCA, notBefore,, SIGN_ALGO);
//根证书签发生成实体证书
X509Certificate eccEmqCert = CertUtils.createUserCert(crt, eccCaKey.getPrivate(), eccEmKey.getPublic(), subjSVR, notBefore, , SIGN_ALGO);
//写入证书到文件
SSLUtils.exportPemCrtFile(crt.getEncoded(),basePath + "eccRootCert.crt");
SSLUtils.exportDerKeyFile(eccCaKey.getPrivate().getEncoded(),basePath + "eccRootCert.key");
SSLUtils.savePrivateKeyAsPEM(eccCaKey.getPrivate(), basePath + "eccRootCertPem.key");
SSLUtils.exportPemCrtFile(eccEmqCert.getEncoded(),basePath + "eccEmqCert.crt");
SSLUtils.exportDerKeyFile(eccEmKey.getPrivate().getEncoded(),basePath + "eccEmqCert.key");
SSLUtils.savePrivateKeyAsPEM(eccEmKey.getPrivate(), basePath + "eccEmqCertPem.key");
}
6. 遇到的小麻烦
1)证书的有效时间和验证服务器的时间不同步导致异常
[root@mq2 ecc]# openssl verify -CAfile eccRootCert.crt eccEmqCert.crt
eccEmqCert.crt: CN = IOT_ECC_CA, C = CN, ST = Hubei, L = Wuhan, O = TKCloud, OU = TaiKang
error at depth lookup:certificate is not yet valid
等一会后,同样的证书,同样的操作,就可以了(生成的证书里面设置的有效时间范围,和当前验证操作,即执行openssl的服务的时间没有同步,服务器时间慢了点)
[root@mq2 ecc]# openssl verify -CAfile eccRootCert.crt eccEmqCert.crt
eccEmqCert.crt: OK
[root@ws2 ecc]# mosquitto_pub -d -h 10.95.197.8 -p -t taikang/rulee -i client18 --cafile /opt/ecc/eccRootCert.crt --cert /opt/ecc/eccDevCert.crt --key /opt/ecc/eccDevCertPem.key -u shihuc -P shihuc -m "are you ok, emqttd"
Client client18 sending CONNECT
OpenSSL Error: error::SSL routines:ssl3_get_server_certificate:certificate verify failed
Error: A TLS error occurred.
上述错误信息,也是证书的有效时间和服务器时间不同步,参照上面的错误。
2)openssl的版本不同导致的查看证书出现异常
[root@mq2 ecc]# openssl x509 -in eccRootCert.crt -noout -text
Certificate:
Data:
Version: (0x2)
Serial Number: (0x5cbfe862)
Signature Algorithm: ecdsa-with-SHA256
Issuer: CN=IOT_ECC_CA, C=CN, ST=Hubei, L=Wuhan, O=TKCloud, OU=TaiKang
Validity
Not Before: Apr :: GMT
Not After : Apr :: GMT
Subject: CN=IOT_ECC_CA, C=CN, ST=Hubei, L=Wuhan, O=TKCloud, OU=TaiKang
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: ( bit)
pub:
:::e6::8d::b2::d2::::f9:d5:
b3:f4::f9::2e:ad::d1:::af:ad:c3:0a:
3c:::f3:::::a9:b9::d7:b3::6b:
5d:::c6::b5::f3:fb:dd:a6:1c::::
c1:b0::5c:
ASN1 OID: prime256v1
NIST CURVE: P-
X509v3 extensions:
X509v3 Authority Key Identifier:
keyid:0F::::B1:7F:AA::BE:::E3::F1:0F:EE::CB:C1:E9 X509v3 Basic Constraints:
CA:TRUE
X509v3 Subject Key Identifier:
0F::::B1:7F:AA::BE:::E3::F1:0F:EE::CB:C1:E9
Signature Algorithm: ecdsa-with-SHA256
:::::f5:d5:3b::8a::af:c7:9a:::f9:4b:
::0d:bb:::dc:eb:::::::::2d:d5:
:::f6:c3:ff:8e:::cd:f2:a9:a9::::d3:0a:
:9a:::::b4:fc:7c:cc::e8::::
[root@mq2 ecc]# openssl version
OpenSSL 1.0.2k-fips 26 Jan 2017
同一个证书,在另外一个服务器上查看:
[root@tkwh-kfcs-app2 java]# openssl x509 -in eccRootCert.crt -noout -text
Certificate:
Data:
Version: (0x2)
Serial Number: (0x5cbfb2ab)
Signature Algorithm: ecdsa-with-SHA256
Issuer: CN=IOT_ECC_CA, C=CN, ST=Hubei, L=Wuhan, O=TKCloud, OU=TaiKang
Validity
Not Before: Apr :: GMT
Not After : Apr :: GMT
Subject: CN=IOT_ECC_CA, C=CN, ST=Hubei, L=Wuhan, O=TKCloud, OU=TaiKang
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Unable to load Public Key
139880214046624:error:100AE081:elliptic curve routines:EC_GROUP_new_by_curve_name:unknown group:ec_curve.c:371:
139880214046624:error:100D7010:elliptic curve routines:ECKEY_PUB_DECODE:EC lib:ec_ameth.c:206:
139880214046624:error:0B07707D:x509 certificate routines:X509_PUBKEY_get:public key decode error:x_pubkey.c:164:
X509v3 extensions:
X509v3 Authority Key Identifier:
keyid:::AB:::C5:DA:BD:::9C:BA:E5:::::1C:E2:AF X509v3 Basic Constraints:
CA:TRUE
X509v3 Subject Key Identifier:
::AB:::C5:DA:BD:::9C:BA:E5:::::1C:E2:AF
Signature Algorithm: ecdsa-with-SHA256
::::5e:f6:fa:::6f::1e:f6::1f::2c:a3:
c7:a8:::a1:8f:::::f2:e4:0d:e5:4b:a8:d2:a5:
::4c:6f:8b:2b:d4:5d::b3:fd:ba:3e:::::dc:
:f5:a9::7e:2f:e8:e9:7b:7b:4c::e0:bc:d5:
[root@tkwh-kfcs-app2 java]# openssl version
OpenSSL 1.0.1e-fips 11 Feb 2013
好了,到这里,ECC证书创建和基本的验证过程,到此结束,有相关需求或者探讨的,可以关注我的博客,一起深入。
MQTT研究之EMQ:【CoAP协议的ECC证书研究】的更多相关文章
- MQTT研究之EMQ:【CoAP协议应用开发】
本博文的重点是尝试CoAP协议的应用开发,其中包含CoAP协议中一个重要的开源工具libcoap的安装和遇到的问题调研.当然,为了很好的将EMQ的CoAP协议网关用起来,也调研了下EMQ体系下,CoA ...
- MQTT研究之EMQ:【EMQX使用中的一些问题记录(2)】
我的测试环境: Linux: CentOS7 EMQX:V3.2.3 题外话: 这里主要介绍Websocket的支持问题. 对ws的支持比较正常,但是对wss的支持,调了较长的时间,没有成功. Jav ...
- 转:XMPP协议、MQTT协议、HTTP协议、CoAP协议的基本比较
一.先看下相关国外的专业数据对四大协议的比较: Protocol CoAP XMP ...
- MQTT研究之EMQ:【EMQ之HTTP认证/访问控制】
今天进行验证的逻辑是EMQ的http的Auth以及ACL的逻辑. 首先,参照HTTP插件认证配置的说明文档进行基本的配置, 我的配置内容如下: ##-------------------------- ...
- MQTT研究之EMQ:【JAVA代码构建X509证书【续集】】
openssl创建私钥,获取公钥,创建证书都是比较简单的,就几个指令,很快就可以搞定,之所以说简单,是因为证书里面的基本参数配置不需要我们组装,只需要将命令行里面需要的几个参数配置进去即可.但是呢,用 ...
- MQTT研究之EMQ:【SSL证书链验证】
1. 创建证书链(shell脚本) 客户端证书链关系: rootCA-->chainca1-->chainca2-->chainca3 ca caCert1 caCert2 caCe ...
- MQTT研究之EMQ:【wireshark抓包分析】
基于上篇博文[SSL双向验证]的环境基础,进行消息的具体梳理. 环境基础信息: . 单台Linux CentOS7.2系统,安装一个EMQTTD的实例broker. . emq的版本2.3.11. . ...
- 无线物联网中CoAP协议的研究与实现【转】
无线物联网中CoAP协议的研究与实现 时间:2013-04-09 来源:电子科技 作者:汤春明,张 荧,吴宇平 关键字:CoAP 无线 物联网 协议 摘要:由于物联网中的很多设备都是资源受 ...
- 转战物联网·基础篇09-选择MQTT协议还是CoAP协议
前面章节介绍过,MQTT协议和CoAP协议都是物联网中比较流行的协议,都对传输量做了很大的精简,传输开销小,以适应物理网的网络环境. XMPP协议也有人说是适合物联网通信的,但它是基于XML, ...
随机推荐
- VUE router-view key 属性解释
router-view 作用, 你可以 router-view 当做是一个容器,它渲染的组件是你使用 vue-router 指定的. <template> <section clas ...
- Linux centos关机和重启命令
Linux centos重启命令: 1.reboot 普通重启 2.shutdown -r now 立刻重启(root用户使用) 3.shutdown -r 10 过10分钟自动重启(root用户 ...
- Linux文本处理sed、软件包管理、磁盘存储、文件系统和挂载
Linux文本处理工具sed.软件包管理.磁盘存储及文件系统 文本处理工具sed巧妙用法 1.通过sed获取文件路径的基名和目录名 思路:采用正则表达式将文本字符串分组,取对应的分组后向引用即可. 获 ...
- 使用Jedis操作Redis数据库
Redis不仅是使用命令来操作,现在基本上主流的语言都有客户端支持,比如java.C.C#.C++.php.Node.js.Go等. 在官方网站里列一些Java的客户端,有Jedis.Redisson ...
- 【时空大数据】Access 到 Postgres 数据迁移遇到的ODBC坑----驱动程序和应用程序之间的体系结构不匹配
1.安装Postgres10 2.安装Postgis插件 3.创建数据库 4.执行postgis脚本插件:参考https://www.cnblogs.com/defineconst/p/1064853 ...
- idea 将java导出为可执行jar及导入jar依赖
使用maven可以很好的帮助我们进行依赖的管理,也可以使用maven的jar包打包插件构建出可运行的jar.那针对不是用maven进行管理的普通java项目,可以通过以下方式导出可执行的jar包以及导 ...
- 理解serverless无服务架构原理(一)
阅读目录 一:什么是serverless无服务? 二:与传统模式架构区别? 三:serverless优缺点? 四:使用serverless的应用场景有哪些? 回到顶部 一:什么是serverless无 ...
- Opentrains 1519 G——最小圆覆盖
题目 给出 $n$ 个定义在区间 $[0, 1]$ 上的一次函数 $f_i(x) = a_ix+b_i$,定义两个函数的距离为: $$dist(f,g) = \left(\max_{0\leq i\l ...
- CF1105D-Kilani and the Game-(多向bfs)
http://codeforces.com/problemset/problem/1105/D 题意:有一片矩阵区域,一开始有多个势力比如1,2,3,4....9,从势力1开始轮流向外扩张,地图上为‘ ...
- LeetCode 1234. Replace the Substring for Balanced String
原题链接在这里:https://leetcode.com/problems/replace-the-substring-for-balanced-string/ 题目: You are given a ...