跳到主要内容

固件请求UOTA下载地址之TCP协议

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 概览

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 一、概述 (固件UOTA TCP协议)

一、概述 (固件UOTA TCP协议)

本文档描述了基于TCP协议的UOTA(Over-The-Air Update)固件更新接入方式。与HTTP协议版本相比,TCP协议版本提供了更高的性能和更低的延迟,适用于对实时性要求较高的设备端应用。


核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 1.1 协议特点 (固件UOTA TCP协议)

1.1 协议特点 (固件UOTA TCP协议)

  • 基于TCP长连接,减少连接建立开销
  • 使用JSON格式进行消息传输
  • 支持AES加密保证数据安全
  • 消息采用换行符(\n)作为分隔符
  • 服务端主动推送时间戳,简化客户端实现

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 1.2 服务器地址信息 (固件UOTA TCP协议)

1.2 服务器地址信息 (固件UOTA TCP协议)

  • 测试环境:192.168.1.87:8520
  • 线上环境:待定

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 二、TCP消息协议格式 (固件UOTA TCP协议)

二、TCP消息协议格式 (固件UOTA TCP协议)


核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 2.1 消息结构 (固件UOTA TCP协议)

2.1 消息结构 (固件UOTA TCP协议)

所有TCP消息均采用JSON格式,结构如下:

{
"type": "消息类型",
"data": "消息数据",
"header": {
"sdkVersion": "SDK版本",
"ignoreVerificationTime": true/false,
"encrypt": true/false
}
}

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 2.2 消息类型定义 (固件UOTA TCP协议)

2.2 消息类型定义 (固件UOTA TCP协议)

  • TIMESTAMP_RESPONSE: 时间戳响应(服务端→客户端)
  • UOTA_INFO_REQUEST: UOTA信息请求(客户端→服务端)
  • UOTA_INFO_RESPONSE: UOTA信息响应(服务端→客户端)
  • ERROR_RESPONSE: 错误响应(服务端→客户端)

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 2.3 消息头字段说明 (固件UOTA TCP协议)

2.3 消息头字段说明 (固件UOTA TCP协议)

  • sdkVersion: SDK版本号,对应HTTP协议中的sdk-version请求头
  • ignoreVerificationTime: 是否忽略时间戳校验(仅测试环境有效)
  • encrypt: 是否加密响应数据(仅测试环境有效,生产环境强制加密)

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 三、通信流程 (固件UOTA TCP协议)

三、通信流程 (固件UOTA TCP协议)


核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 3.1 连接建立 (固件UOTA TCP协议)

3.1 连接建立 (固件UOTA TCP协议)

  1. 客户端连接到TCP服务器
  2. 服务端立即返回当前时间戳

时间戳响应示例:

{
"type": "TIMESTAMP_RESPONSE",
"data": "1761104391386"
}

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 3.2 UOTA信息请求 (固件UOTA TCP协议)

3.2 UOTA信息请求 (固件UOTA TCP协议)

客户端收到时间戳后,构造UOTA信息请求。

请求数据结构(加密前):

{
"mac": "A8:20:06:B7:C8:B9",
"cpu": "02c0008145f0462078a3840038350b53",
"time": 1761104391386,
"platform": "allwinner"
}

字段说明:

  • mac: 设备MAC地址
  • cpu: 设备CPU标识,获取不到则传null
  • time: 服务端返回的时间戳
  • platform: 固件平台,支持amlogic、rockchip、allwinner

完整请求消息示例:

{
"type": "UOTA_INFO_REQUEST",
"data": "加密后的请求数据",
"header": {
"sdkVersion": "allwinner-202510-01",
"ignoreVerificationTime": true,
"encrypt": true
}
}

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 3.3 UOTA信息响应 (固件UOTA TCP协议)

3.3 UOTA信息响应 (固件UOTA TCP协议)

服务端处理请求后返回固件信息。

响应数据结构(解密后):

{
"url": "http://192.168.1.87:8742/app-api/infra/file/download/redirect/1757560816080/app-netservice-3.4.9-allwinner-20250911-debug.apk",
"size": 4747480,
"packageName": "com.android.netservice",
"versionCode": 49,
"md5": "c7d614b68b94ef0ca470fb30fc3a79ec"
}

完整响应消息示例:

{
"type": "UOTA_INFO_RESPONSE",
"data": "加密后的响应数据"
}

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 3.4 错误处理 (固件UOTA TCP协议)

3.4 错误处理 (固件UOTA TCP协议)

当请求处理失败时,服务端返回错误响应:

{
"type": "ERROR_RESPONSE",
"data": "错误信息描述"
}

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 四、加密算法 (固件UOTA TCP协议)

四、加密算法 (固件UOTA TCP协议)


核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 4.1 加密参数 (固件UOTA TCP协议)

4.1 加密参数 (固件UOTA TCP协议)

  • 算法: AES-CBC
  • 填充: PKCS5Padding
  • 密钥长度: 16、24或32字节(对应AES-128、AES-192、AES-256)
  • IV: 16字节随机生成
  • 编码: Base64

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 4.2 密钥配置 (固件UOTA TCP协议)

4.2 密钥配置 (固件UOTA TCP协议)

每个固件版本都应配置独立的密钥:

  • 测试环境密钥: 12345678123456781234567812345678
  • 生产环境: 根据sdkVersion从服务端配置获取

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 4.3 加密流程 (固件UOTA TCP协议)

4.3 加密流程 (固件UOTA TCP协议)

  1. 生成16字节随机IV
  2. 使用AES-CBC模式加密明文
  3. 将IV和密文拼接(IV在前)
  4. 对拼接结果进行Base64编码

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 4.4 解密流程 (固件UOTA TCP协议)

4.4 解密流程 (固件UOTA TCP协议)

  1. Base64解码得到拼接数据
  2. 分离前16字节作为IV
  3. 剩余数据作为密文
  4. 使用AES-CBC模式解密

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 五、Java实现示例 (固件UOTA TCP协议)

五、Java实现示例 (固件UOTA TCP协议)


核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 5.1 加密方法 (固件UOTA TCP协议)

5.1 加密方法 (固件UOTA TCP协议)

public static String encrypt(String plainText, String secretKey) throws Exception {
// 将密钥转换为字节数组并验证长度
byte[] keyBytes = validateKey(secretKey);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");

// 生成随机初始化向量(IV)
byte[] ivBytes = new byte[16];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(ivBytes);
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);

// 初始化加密器
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);

// 执行加密
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));

// 组合IV和密文(IV前置方案)
byte[] combined = new byte[ivBytes.length + encryptedBytes.length];
System.arraycopy(ivBytes, 0, combined, 0, ivBytes.length);
System.arraycopy(encryptedBytes, 0, combined, ivBytes.length, encryptedBytes.length);

// 返回Base64编码的字符串
return Base64.getEncoder().encodeToString(combined);
}

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 5.2 解密方法 (固件UOTA TCP协议)

5.2 解密方法 (固件UOTA TCP协议)

public static String decrypt(String encryptedText, String secretKey) throws Exception {
// 将密钥转换为字节数组并验证长度
byte[] keyBytes = validateKey(secretKey);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");

// Base64解码
byte[] combined = Base64.getDecoder().decode(encryptedText);

// 分离IV和密文(前16字节是IV)
byte[] ivBytes = new byte[16];
byte[] encryptedBytes = new byte[combined.length - ivBytes.length];
System.arraycopy(combined, 0, ivBytes, 0, ivBytes.length);
System.arraycopy(combined, ivBytes.length, encryptedBytes, 0, encryptedBytes.length);
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);

// 初始化解密器
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);

// 执行解密并返回UTF-8字符串
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
return new String(decryptedBytes, StandardCharsets.UTF_8);
}

// 密钥验证(支持128/192/256位)
private static byte[] validateKey(String key) {
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
if (keyBytes.length != 16 && keyBytes.length != 24 && keyBytes.length != 32) {
throw new IllegalArgumentException("密钥长度必须是16、24或32字节(对应128/192/256位)");
}
return keyBytes;
}

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 六、C语言客户端实现示例 (固件UOTA TCP协议)

六、C语言客户端实现示例 (固件UOTA TCP协议)


核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 6.1 依赖库 (固件UOTA TCP协议)

6.1 依赖库 (固件UOTA TCP协议)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <json-c/json.h>

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 6.2 Base64编解码 (固件UOTA TCP协议)

6.2 Base64编解码 (固件UOTA TCP协议)

#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/buffer.h>

char* base64_encode(const unsigned char* input, int length) {
BIO *bio, *b64;
BUF_MEM *bufferPtr;

b64 = BIO_new(BIO_f_base64());
bio = BIO_new(BIO_s_mem());
bio = BIO_push(b64, bio);

BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
BIO_write(bio, input, length);
BIO_flush(bio);
BIO_get_mem_ptr(bio, &bufferPtr);

char* result = malloc(bufferPtr->length + 1);
memcpy(result, bufferPtr->data, bufferPtr->length);
result[bufferPtr->length] = '\0';

BIO_free_all(bio);
return result;
}

unsigned char* base64_decode(const char* input, int* output_length) {
BIO *bio, *b64;
int decode_len = strlen(input);
unsigned char* buffer = malloc(decode_len);

bio = BIO_new_mem_buf(input, -1);
b64 = BIO_new(BIO_f_base64());
bio = BIO_push(b64, bio);

BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
*output_length = BIO_read(bio, buffer, decode_len);

BIO_free_all(bio);
return buffer;
}

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 6.3 AES加密解密 (固件UOTA TCP协议)

6.3 AES加密解密 (固件UOTA TCP协议)

char* aes_encrypt(const char* plaintext, const char* key) {
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
unsigned char iv[16];
unsigned char* ciphertext;
unsigned char* combined;
char* result;

// 生成随机IV
if (RAND_bytes(iv, 16) != 1) {
return NULL;
}

// 创建加密上下文
ctx = EVP_CIPHER_CTX_new();
if (!ctx) return NULL;

// 初始化加密
if (EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, (unsigned char*)key, iv) != 1) {
EVP_CIPHER_CTX_free(ctx);
return NULL;
}

// 分配密文缓冲区
int plaintext_len = strlen(plaintext);
ciphertext = malloc(plaintext_len + AES_BLOCK_SIZE);

// 执行加密
if (EVP_EncryptUpdate(ctx, ciphertext, &len, (unsigned char*)plaintext, plaintext_len) != 1) {
free(ciphertext);
EVP_CIPHER_CTX_free(ctx);
return NULL;
}
ciphertext_len = len;

// 完成加密
if (EVP_EncryptFinal_ex(ctx, ciphertext + len, &len) != 1) {
free(ciphertext);
EVP_CIPHER_CTX_free(ctx);
return NULL;
}
ciphertext_len += len;

// 组合IV和密文
combined = malloc(16 + ciphertext_len);
memcpy(combined, iv, 16);
memcpy(combined + 16, ciphertext, ciphertext_len);

// Base64编码
result = base64_encode(combined, 16 + ciphertext_len);

// 清理资源
free(ciphertext);
free(combined);
EVP_CIPHER_CTX_free(ctx);

return result;
}

char* aes_decrypt(const char* encrypted_text, const char* key) {
int encrypted_len;
unsigned char* encrypted_data = base64_decode(encrypted_text, &encrypted_len);

if (encrypted_len < 16) {
free(encrypted_data);
return NULL;
}

unsigned char iv[16];
memcpy(iv, encrypted_data, 16);

unsigned char* ciphertext = encrypted_data + 16;
int ciphertext_len = encrypted_len - 16;

EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
free(encrypted_data);
return NULL;
}

if (EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, (unsigned char*)key, iv) != 1) {
EVP_CIPHER_CTX_free(ctx);
free(encrypted_data);
return NULL;
}

unsigned char* plaintext = malloc(ciphertext_len + AES_BLOCK_SIZE);
int len;
int plaintext_len;

if (EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len) != 1) {
free(plaintext);
EVP_CIPHER_CTX_free(ctx);
free(encrypted_data);
return NULL;
}
plaintext_len = len;

if (EVP_DecryptFinal_ex(ctx, plaintext + len, &len) != 1) {
free(plaintext);
EVP_CIPHER_CTX_free(ctx);
free(encrypted_data);
return NULL;
}
plaintext_len += len;

plaintext[plaintext_len] = '\0';

char* result = strdup((char*)plaintext);

free(plaintext);
EVP_CIPHER_CTX_free(ctx);
free(encrypted_data);

return result;
}

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 6.4 TCP客户端主程序 (固件UOTA TCP协议)

6.4 TCP客户端主程序 (固件UOTA TCP协议)

#define BUFFER_SIZE 8192
#define SERVER_IP "192.168.1.87"
#define SERVER_PORT 8520

int main() {
int sock;
struct sockaddr_in server_addr;
char buffer[BUFFER_SIZE];
char* timestamp = NULL;

// 创建socket
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("Socket creation failed");
return -1;
}

// 设置服务器地址
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr);

// 连接服务器
if (connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
perror("Connection failed");
close(sock);
return -1;
}

printf("Connected to server %s:%d\n", SERVER_IP, SERVER_PORT);

// 接收时间戳响应
memset(buffer, 0, BUFFER_SIZE);
int bytes_received = recv(sock, buffer, BUFFER_SIZE - 1, 0);
if (bytes_received > 0) {
buffer[bytes_received] = '\0';
printf("Received: %s\n", buffer);

// 解析时间戳
json_object* root = json_tokener_parse(buffer);
json_object* type_obj;
json_object* data_obj;

if (json_object_object_get_ex(root, "type", &type_obj) &&
json_object_object_get_ex(root, "data", &data_obj)) {

const char* type = json_object_get_string(type_obj);
if (strcmp(type, "TIMESTAMP_RESPONSE") == 0) {
timestamp = strdup(json_object_get_string(data_obj));
printf("Received timestamp: %s\n", timestamp);
}
}
json_object_put(root);
}

if (timestamp) {
// 构造请求数据
json_object* request_data = json_object_new_object();
json_object_object_add(request_data, "mac", json_object_new_string("A8:20:06:B7:C8:B9"));
json_object_object_add(request_data, "cpu", json_object_new_string("02c0008145f0462078a3840038350b53"));
json_object_object_add(request_data, "time", json_object_new_int64(atoll(timestamp)));
json_object_object_add(request_data, "platform", json_object_new_string("allwinner"));

const char* json_string = json_object_to_json_string(request_data);

// 加密请求数据
const char* secret_key = "12345678123456781234567812345678";
char* encrypted_data = aes_encrypt(json_string, secret_key);

// 构造完整请求消息
json_object* header = json_object_new_object();
json_object_object_add(header, "sdkVersion", json_object_new_string("allwinner-202510-01"));
json_object_object_add(header, "ignoreVerificationTime", json_object_new_boolean(1));
json_object_object_add(header, "encrypt", json_object_new_boolean(1));

json_object* request_msg = json_object_new_object();
json_object_object_add(request_msg, "type", json_object_new_string("UOTA_INFO_REQUEST"));
json_object_object_add(request_msg, "data", json_object_new_string(encrypted_data));
json_object_object_add(request_msg, "header", header);

const char* request_json = json_object_to_json_string(request_msg);

// 发送请求(添加换行符)
char* request_with_newline = malloc(strlen(request_json) + 2);
sprintf(request_with_newline, "%s\n", request_json);

send(sock, request_with_newline, strlen(request_with_newline), 0);
printf("Sent UOTA request\n");

// 接收响应
memset(buffer, 0, BUFFER_SIZE);
bytes_received = recv(sock, buffer, BUFFER_SIZE - 1, 0);
if (bytes_received > 0) {
buffer[bytes_received] = '\0';
printf("Received response: %s\n", buffer);

// 解析响应
json_object* response = json_tokener_parse(buffer);
json_object* response_type;
json_object* response_data;

if (json_object_object_get_ex(response, "type", &response_type) &&
json_object_object_get_ex(response, "data", &response_data)) {

const char* type = json_object_get_string(response_type);
const char* data = json_object_get_string(response_data);

if (strcmp(type, "UOTA_INFO_RESPONSE") == 0) {
// 解密响应数据
char* decrypted_data = aes_decrypt(data, secret_key);
if (decrypted_data) {
printf("Decrypted response: %s\n", decrypted_data);
free(decrypted_data);
}
} else if (strcmp(type, "ERROR_RESPONSE") == 0) {
printf("Error response: %s\n", data);
}
}
json_object_put(response);
}

// 清理资源
free(encrypted_data);
free(request_with_newline);
json_object_put(request_data);
json_object_put(request_msg);
free(timestamp);
}

close(sock);
return 0;
}

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 七、C++客户端实现示例 (固件UOTA TCP协议)

七、C++客户端实现示例 (固件UOTA TCP协议)


核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 7.1 头文件和依赖 (固件UOTA TCP协议)

7.1 头文件和依赖 (固件UOTA TCP协议)

#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <json/json.h>

class UotaTcpClient {
private:
std::string server_ip;
int server_port;
int socket_fd;

public:
UotaTcpClient(const std::string& ip, int port)
: server_ip(ip), server_port(port), socket_fd(-1) {}

~UotaTcpClient() {
disconnect();
}

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 7.2 Base64编解码类 (固件UOTA TCP协议)

7.2 Base64编解码类 (固件UOTA TCP协议)

class Base64 {
public:
static std::string encode(const std::vector<unsigned char>& input) {
BIO *bio, *b64;
BUF_MEM *bufferPtr;

b64 = BIO_new(BIO_f_base64());
bio = BIO_new(BIO_s_mem());
bio = BIO_push(b64, bio);

BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
BIO_write(bio, input.data(), input.size());
BIO_flush(bio);
BIO_get_mem_ptr(bio, &bufferPtr);

std::string result(bufferPtr->data, bufferPtr->length);
BIO_free_all(bio);
return result;
}

static std::vector<unsigned char> decode(const std::string& input) {
BIO *bio, *b64;
std::vector<unsigned char> buffer(input.length());

bio = BIO_new_mem_buf(input.c_str(), -1);
b64 = BIO_new(BIO_f_base64());
bio = BIO_push(b64, bio);

BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
int decoded_length = BIO_read(bio, buffer.data(), input.length());
buffer.resize(decoded_length);

BIO_free_all(bio);
return buffer;
}
};

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 7.3 AES加密解密类 (固件UOTA TCP协议)

7.3 AES加密解密类 (固件UOTA TCP协议)

class AESCrypto {
private:
static const int IV_SIZE = 16;

public:
static std::string encrypt(const std::string& plaintext, const std::string& key) {
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) return "";

// 生成随机IV
std::vector<unsigned char> iv(IV_SIZE);
if (RAND_bytes(iv.data(), IV_SIZE) != 1) {
EVP_CIPHER_CTX_free(ctx);
return "";
}

// 初始化加密
if (EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL,
reinterpret_cast<const unsigned char*>(key.c_str()),
iv.data()) != 1) {
EVP_CIPHER_CTX_free(ctx);
return "";
}

// 执行加密
std::vector<unsigned char> ciphertext(plaintext.length() + AES_BLOCK_SIZE);
int len;
int ciphertext_len;

if (EVP_EncryptUpdate(ctx, ciphertext.data(), &len,
reinterpret_cast<const unsigned char*>(plaintext.c_str()),
plaintext.length()) != 1) {
EVP_CIPHER_CTX_free(ctx);
return "";
}
ciphertext_len = len;

if (EVP_EncryptFinal_ex(ctx, ciphertext.data() + len, &len) != 1) {
EVP_CIPHER_CTX_free(ctx);
return "";
}
ciphertext_len += len;

// 组合IV和密文
std::vector<unsigned char> combined(IV_SIZE + ciphertext_len);
std::copy(iv.begin(), iv.end(), combined.begin());
std::copy(ciphertext.begin(), ciphertext.begin() + ciphertext_len,
combined.begin() + IV_SIZE);

EVP_CIPHER_CTX_free(ctx);
return Base64::encode(combined);
}

static std::string decrypt(const std::string& encrypted_text, const std::string& key) {
std::vector<unsigned char> encrypted_data = Base64::decode(encrypted_text);

if (encrypted_data.size() < IV_SIZE) {
return "";
}

// 分离IV和密文
std::vector<unsigned char> iv(encrypted_data.begin(),
encrypted_data.begin() + IV_SIZE);
std::vector<unsigned char> ciphertext(encrypted_data.begin() + IV_SIZE,
encrypted_data.end());

EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) return "";

if (EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL,
reinterpret_cast<const unsigned char*>(key.c_str()),
iv.data()) != 1) {
EVP_CIPHER_CTX_free(ctx);
return "";
}

std::vector<unsigned char> plaintext(ciphertext.size() + AES_BLOCK_SIZE);
int len;
int plaintext_len;

if (EVP_DecryptUpdate(ctx, plaintext.data(), &len,
ciphertext.data(), ciphertext.size()) != 1) {
EVP_CIPHER_CTX_free(ctx);
return "";
}
plaintext_len = len;

if (EVP_DecryptFinal_ex(ctx, plaintext.data() + len, &len) != 1) {
EVP_CIPHER_CTX_free(ctx);
return "";
}
plaintext_len += len;

EVP_CIPHER_CTX_free(ctx);
return std::string(reinterpret_cast<char*>(plaintext.data()), plaintext_len);
}
};

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 7.4 TCP客户端主要方法 (固件UOTA TCP协议)

7.4 TCP客户端主要方法 (固件UOTA TCP协议)

    bool connect() {
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd < 0) {
std::cerr << "Socket creation failed" << std::endl;
return false;
}

struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(server_port);
inet_pton(AF_INET, server_ip.c_str(), &server_addr.sin_addr);

if (::connect(socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
std::cerr << "Connection failed" << std::endl;
close(socket_fd);
socket_fd = -1;
return false;
}

std::cout << "Connected to server " << server_ip << ":" << server_port << std::endl;
return true;
}

void disconnect() {
if (socket_fd >= 0) {
close(socket_fd);
socket_fd = -1;
}
}

std::string receiveMessage() {
char buffer[8192];
memset(buffer, 0, sizeof(buffer));

int bytes_received = recv(socket_fd, buffer, sizeof(buffer) - 1, 0);
if (bytes_received > 0) {
buffer[bytes_received] = '\0';
return std::string(buffer);
}
return "";
}

bool sendMessage(const std::string& message) {
std::string msg_with_newline = message + "\n";
int bytes_sent = send(socket_fd, msg_with_newline.c_str(), msg_with_newline.length(), 0);
return bytes_sent > 0;
}

bool requestUotaInfo() {
// 接收时间戳
std::string timestamp_response = receiveMessage();
if (timestamp_response.empty()) {
std::cerr << "Failed to receive timestamp" << std::endl;
return false;
}

std::cout << "Received: " << timestamp_response << std::endl;

// 解析时间戳
Json::Value root;
Json::Reader reader;
if (!reader.parse(timestamp_response, root)) {
std::cerr << "Failed to parse timestamp response" << std::endl;
return false;
}

if (root["type"].asString() != "TIMESTAMP_RESPONSE") {
std::cerr << "Invalid timestamp response type" << std::endl;
return false;
}

std::string timestamp = root["data"].asString();
std::cout << "Received timestamp: " << timestamp << std::endl;

// 构造请求数据
Json::Value request_data;
request_data["mac"] = "A8:20:06:B7:C8:B9";
request_data["cpu"] = "02c0008145f0462078a3840038350b53";
request_data["time"] = std::stoll(timestamp);
request_data["platform"] = "allwinner";

Json::StreamWriterBuilder builder;
builder["indentation"] = "";
std::string json_string = Json::writeString(builder, request_data);

// 加密请求数据
const std::string secret_key = "12345678123456781234567812345678";
std::string encrypted_data = AESCrypto::encrypt(json_string, secret_key);

// 构造完整请求消息
Json::Value header;
header["sdkVersion"] = "allwinner-202510-01";
header["ignoreVerificationTime"] = true;
header["encrypt"] = true;

Json::Value request_msg;
request_msg["type"] = "UOTA_INFO_REQUEST";
request_msg["data"] = encrypted_data;
request_msg["header"] = header;

std::string request_json = Json::writeString(builder, request_msg);

// 发送请求
if (!sendMessage(request_json)) {
std::cerr << "Failed to send request" << std::endl;
return false;
}

std::cout << "Sent UOTA request" << std::endl;

// 接收响应
std::string response = receiveMessage();
if (response.empty()) {
std::cerr << "Failed to receive response" << std::endl;
return false;
}

std::cout << "Received response: " << response << std::endl;

// 解析响应
Json::Value response_root;
if (!reader.parse(response, response_root)) {
std::cerr << "Failed to parse response" << std::endl;
return false;
}

std::string response_type = response_root["type"].asString();
std::string response_data = response_root["data"].asString();

if (response_type == "UOTA_INFO_RESPONSE") {
// 解密响应数据
std::string decrypted_data = AESCrypto::decrypt(response_data, secret_key);
if (!decrypted_data.empty()) {
std::cout << "Decrypted response: " << decrypted_data << std::endl;
}
} else if (response_type == "ERROR_RESPONSE") {
std::cout << "Error response: " << response_data << std::endl;
}

return true;
}
};

// 主函数
int main() {
UotaTcpClient client("192.168.1.87", 8520);

if (client.connect()) {
client.requestUotaInfo();
}

return 0;
}

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 八、编译说明 (固件UOTA TCP协议)

八、编译说明 (固件UOTA TCP协议)


核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 8.1 C语言版本编译 (固件UOTA TCP协议)

8.1 C语言版本编译 (固件UOTA TCP协议)

# 安装依赖(Ubuntu/Debian)
sudo apt-get install libssl-dev libjson-c-dev

# 编译
gcc -o uota_client_c uota_client.c -lssl -lcrypto -ljson-c

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 8.2 C++版本编译 (固件UOTA TCP协议)

8.2 C++版本编译 (固件UOTA TCP协议)

# 安装依赖(Ubuntu/Debian)
sudo apt-get install libssl-dev libjsoncpp-dev

# 编译
g++ -o uota_client_cpp uota_client.cpp -lssl -lcrypto -ljsoncpp

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 九、测试验证 (固件UOTA TCP协议)

九、测试验证 (固件UOTA TCP协议)


核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 9.1 连接测试 (固件UOTA TCP协议)

9.1 连接测试 (固件UOTA TCP协议)

  1. 启动TCP服务器(端口8520)
  2. 运行客户端程序
  3. 验证连接建立和时间戳接收

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 9.2 UOTA请求测试 (固件UOTA TCP协议)

9.2 UOTA请求测试 (固件UOTA TCP协议)

  1. 验证请求数据加密正确
  2. 验证服务端响应解密正确
  3. 验证固件信息获取成功

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 9.3 错误处理测试 (固件UOTA TCP协议)

9.3 错误处理测试 (固件UOTA TCP协议)

  1. 测试网络连接异常
  2. 测试加密解密异常
  3. 测试服务端错误响应

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 十、注意事项 (固件UOTA TCP协议)

十、注意事项 (固件UOTA TCP协议)

  1. 密钥安全: 生产环境中密钥必须进行混淆处理,避免被反编译获取
  2. 时间戳校验: 生产环境必须启用时间戳校验,防止重放攻击
  3. 网络异常: 客户端需要处理网络断开、超时等异常情况
  4. 内存管理: C/C++版本需要注意内存泄漏问题
  5. 线程安全: 多线程环境下需要考虑线程安全问题

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 十一、与HTTP协议对比 (固件UOTA TCP协议)

十一、与HTTP协议对比 (固件UOTA TCP协议)

特性TCP协议HTTP协议
连接方式长连接短连接
性能更高较低
实现复杂度较高较低
消息格式JSONJSON
加密方式AES-CBCAES-CBC
适用场景高频更新一般更新

核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 十二、测试示例 (固件UOTA TCP协议)

十二、测试示例 (固件UOTA TCP协议)

uota-自定义tcp协议java测试客户端日志.png


核心概念:文档中心 | 固件请求UOTA下载地址之TCP协议 | 十三、交互流程图 (固件UOTA TCP协议)

十三、交互流程图 (固件UOTA TCP协议)

Mermaid Diagram Code:

sequenceDiagram
    participant Device as 设备端
    participant Server as 服务端
    
    Device->>Server: 建立 TCP 连接
    Server-->>Device: TIMESTAMP_RESPONSE (当前时间戳)
    
    Device->>Device: 组装 JSON 数据
    Device->>Device: AES加密 data
    
    Device->>Server: UOTA_INFO_REQUEST <br/>Header: sdkVersion, ignoreVerificationTime<br/>Data: Encrypted String
    
    Server->>Server: 校验 sdkVersion & 密钥
    Server->>Server: 解密 data
    Server->>Server: 校验时间戳
    Server->>Server: 获取固件信息
    Server->>Server: 加密响应数据
    
    alt 处理成功
        Server-->>Device: UOTA_INFO_RESPONSE (Encrypted Data)
        Device->>Device: 解密获取固件 URL
    else 处理失败
        Server-->>Device: ERROR_RESPONSE (Error Message)
    end
AI 问答