服务端 WebService 简介
平台接口地址:详见《宁波市民用建筑能耗监测系统建设实施细则》2018甬DX-05中附录E。
服务端 WebService 与客户端程序通过 HTTP 方式进行交互,所有传输过程中的参数与数据均为经过 AES(128位)加密后的数据。
表计上传间隔时间控制在60分钟一次
AES 加密
说明
(1)加密位:128位
(2)加密模式:CBC
(3)填充模式:Zeros
加密详细流程
WebService 接口接收的数据及返回调用方的数据均为经过AES加密后并将加密后的 byte[]
数组中的每一位十进制数通过‘-’连接成字符串形式传输。例如当明文加密后的 byte[] 数组为 byte[] { 12, 25,
112},则传输的数据应为“12-25-112”。
样例:明文为“测试数据”,首先调用加密函数 AESEncrypt 得到加密后的 byte[] 数据,然后通过调用 BytesToString 函数将 byte[]
数据转换成字符串格式,然后将该字符串传到服务端。当然,服务端也会以这种形式加密并转换成字符串格式发送给客户端,所以客户端在接收到该字符串时首先调用
StringToBytes 函数将字符串还原成 byte[] 数据,然后调用解密函数 AESDecrypt 还原成明文。
加密代码
下面是 AES 加解密算法中的 keyArray 和 ivArray:
// AES密钥 AES加密位: 128位,加密模式:CBC, 填充模式:Zeros
private byte[] keyArray = new byte[] {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
};
private byte[] ivArray = new byte[] {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
};
加密算法如下:
// AES 加密
public byte[] AESEncrypt(string text)
{
byte[] data = Encoding.Unicode.GetBytes(text);
SymmetricAlgorithm aes = Rijndael.Create();
aes.Key = keyArray;
aes.IV = ivArray;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.Zeros;
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(data, 0, data.Length);
cs.FlushFinalBlock();
byte[] cipherBytes = ms.ToArray(); // 得到加密后的字节数组
cs.Close();
ms.Close();
aes.Clear();
return cipherBytes;
}
}
}
解密算法如下:
// AES 解密
public string AESDecrypt(byte[] data)
{
SymmetricAlgorithm aes = Rijndael.Create();
aes.Key = keyArray;
aes.IV = ivArray;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.Zeros;
byte[] decryptBytes = new byte[data.Length];
using (MemoryStream ms = new MemoryStream(data))
{
using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Read))
{
cs.Read(decryptBytes, 0, decryptBytes.Length);
cs.Close();
ms.Close();
}
}
aes.Clear();
return System.Text.Encoding.Unicode.GetString(decryptBytes).Replace("\0", " ");
}
其他代码
byte[] 数组与字符串互转。
将 byte[] 转换为字符串,代码如下:
// 将 byte[] 转换为字符串
public string BytesToString(byte[] bt)
{
string str = "";
foreach (var a in bt)
{
if (str != "")
{
str += "-";
}
str += a.ToString();
}
return str;
}
将字符串转换为 byte[],代码如下:
// 将字符串转换为 byte[]
public byte[] StringToBytes(string str)
{
string[] strArray = str.Split('-');
int len = strArray.Length;
byte[] bt = new byte[len];
for (int i = 0; i < len; i++)
{
bt[i] = Convert.ToByte(strArray[i]);
}
return bt;
}
接口总览
当前的平台提供了如下接口:
(1)GetUUID:获取客户端唯一标识符。
(2)GetPassword:获取客户端通讯密码。
(3)Login:客户端登录。
(4)SendHeartBeat:发送心跳包。
(5)GetBuildingData:获取要发送的数据列表。
(6)SendMeterData:发送数据。
通讯过程
1、客户端首先通过调用服务端的 GetUUID
接口来获取客户端唯一标识符。该客户端唯一标识符对于一个客户端身份仅发送一次,所以客户端在接收到该标识符后应妥善保管,若丢失将无法进行正常通讯。若有第二个相同身份的客户端来获取该标识符将无法获得。
2、当客户端获取了客户端唯一标识符后,可调用服务端的 GetPassword
接口来获取客户端通讯登录密码,该密码将在客户端下线后失效。反复重复调用该接口将产生新的密码,并且原来的密码将会失效。
3、当客户端获取到登录密码后,将可以调用服务端的 Login 接口进行客户端登录,登录成功后将返回心跳包配置信息。
4、当客户端获取到心跳包配置信息后,需规范按照心跳包的配置信息定时调用服务端的 SendHeartBeat
接口来发送心跳包数据,若服务端在一定时间内未接收到该客户端的心跳包,则主动将该客户端下线,并将原有的通讯登录密码作废,那么客户端需重新从第2步开始获取新的登录密码才能进行正常通讯。
5、在正常通讯期间,客户端可定时调用服务端的 GetBuildingData 接口来获取需要传输的数据的列表信息。
6、在客户端获取到需传输的数据的列表信息后,需根据列表信息传输客户端本地数据到服务端,每次传输的数据以一栋建筑物为基础分多次上传,调用接口为服务端的
SendMeterData 接口。
7、在正常情况下,客户端需定时不断的进行第4步操作以保持客户端登录状态。客户端每次上传数据时必须先调用第5步骤后再进行第6步骤的操作。