Artikel ini menjelaskan cara menggunakan sertifikat X.509 untuk menghubungkan perangkat berbasis MQTT , file kode contoh ./demos/mqtt_x509_auth_demo.c digunakan.
Informasi latar belakang
Untuk informasi lebih lanjut tentang koneksi berbasis Sertifikat X.509, lihat Ikhtisar.
- Kecuali untuk Langkah 2: Konfigurasikan Fitur yang Diperlukan, langkah-langkah dalam topik ini sama dengan yang ada di topik Contoh.
Langkah 1: Inisialisasi klien
Tambahkan file header.
#include "aiot_state_api.h" #include "aiot_sysdep_api.h" #include "aiot_mqtt_api.h"Tambahkan dependensi dasar dan konfigurasikan fitur output log.
aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile); aiot_state_set_logcb(demo_state_logcb);Panggil operasi aiot_mqtt_init untuk membuat instance klien MQTT dan menginisialisasi parameter default.
mqtt_handle = aiot_mqtt_init(); if (mqtt_handle == NULL) { printf("aiot_mqtt_init gagal\n"); return -1; }
Langkah 2: Konfigurasikan fitur
Panggil operasi aiot_mqtt_setopt untuk mengonfigurasi item-item berikut:
- Atur parameter koneksi.
- Konfigurasikan callback untuk mendapatkan informasi identitas perangkat.
- Konfigurasikan callback untuk memantau status dan menerima pesan.
Untuk informasi lebih lanjut tentang parameter operasi, lihat aiot_mqtt_option_t.
- Atur parameter koneksi.
const char client_cert[] = { "-----BEGIN CERTIFICATE-----\r\n" "MIIDiDCCAnCgAwIBAgIIAJ3GD7c2860wDQYJKoZIhvcNAQELBQAwUzEoMCYGA1UE\r\n" ... ... "v4aDacYavCH03JXKQ6zWpAwnwLcYrbW7XdhtDrqFCj+v6VJ6NDZaTGEW3/I=\r\n" "-----END CERTIFICATE-----\r\n" }; const char client_private_key[] = { "-----BEGIN RSA PRIVATE KEY-----\r\n" "MIIEowIBAAKCAQEApyRaelm4b4sKOlqBywOIR4RIJrYEfNtYIAofMIkkwnClrqgh\r\n" ... ... "mPw5JEAkNBy6wOWepJ9Tv1wY8yFEzV2dVsx3P93p5P3UdZb4M7i0\r\n" "-----END RSA PRIVATE KEY-----\r\n" }; ... int main(int argc, char *argv[]) { int32_t res = STATE_SUCCESS; void *mqtt_handle = NULL; char *host = "x509.itls.cn-shanghai.aliyuncs.com"; uint16_t port = 1883; aiot_sysdep_network_cred_t cred; char *product_key = ""; char *device_name = ""; char *device_secret = ""; ... /* Struktur kredensial keamanan. Untuk menetapkan koneksi TLS, tentukan sertifikat CA dalam struktur ini. */ aiot_sysdep_network_cred_t cred; /* Buat kredensial keamanan untuk SDK agar dapat menetapkan koneksi TLS. */ memset(&cred, 0, sizeof(aiot_sysdep_network_cred_t)); cred.option = AIOT_SYSDEP_NETWORK_CRED_SVRCERT_CA; /* Verifikasi broker MQTT menggunakan sertifikat RSA. */ cred.max_tls_fragment = 16384; /* Fragmen dapat memiliki panjang hingga 16 KB. Nilai opsional lainnya termasuk 4 KB, 2 KB, 1 KB, dan 0,5 KB. */ cred.sni_enabled = 1; /* Ekstensi Server Name Indicator (SNI) didukung saat Anda menetapkan koneksi TLS. */ cred.x509_server_cert = ali_ca_crt; /* Sertifikat root RSA yang digunakan untuk memverifikasi broker MQTT. */ cred.x509_server_cert_len = strlen(ali_ca_crt); /* Panjang sertifikat root RSA. */ /* TODO: Saat menggunakan sertifikat X.509 untuk otentikasi dua arah, Anda harus menambahkan kode berikut untuk menetapkan kredensial keamanan. */ cred.x509_client_cert = client_cert; cred.x509_client_cert_len = strlen(client_cert); cred.x509_client_privkey = client_private_key; cred.x509_client_privkey_len = strlen(client_private_key); /* Tetapkan kredensial keamanan koneksi. */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_NETWORK_CRED, (void *)&cred); ... }Parameter Contoh Deskripsi client_cert[] "-----BEGIN CERTIFICATE-----\r\n" "MIIDiDCCAnCgAwIBAgIIAJ3GD7c2860wDQYJKoZIhvcNAQELBQAwUzEoMCYGA1UE\r\n" ... ... "v4aDacYavCH03JXKQ6zWpAwnwLcYrbW7XdhtDrqFCj+v6VJ6NDZaTGEW3/I=\r\n" "-----END CERTIFICATE-----\r\n"Informasi sertifikat X.509 dari perangkat. Di halaman Detail Perangkat konsol IoT Platform, klik Download di sebelah X.509 Certificate untuk mengunduh informasi sertifikat. Setelah Anda mengekstraksi file sertifikat, ganti nilai parameter ini dengan informasi dalam file
.cerdalam format nilai contoh.Informasi sertifikat terdiri dari beberapa baris string. Elipsis (...) dalam kode sampel menunjukkan string yang dihilangkan. Tambahkan
"di awal dan\r\n"di akhir setiap string.client_private_key[] "-----BEGIN RSA PRIVATE KEY-----\r\n" "MIIEowIBAAKCAQEApyRaelm4b4sKOlqBywOIR4RIJrYEfNtYIAofMIkkwnClrqgh\r\n" ... ... "mPw5JEAkNBy6wOWepJ9Tv1wY8yFEzV2dVsx3P93p5P3UdZb4M7i0\r\n" "-----END RSA PRIVATE KEY-----\r\n"Kunci privat sertifikat X.509. Di halaman Detail Perangkat konsol IoT Platform, klik Download di sebelah X.509 Certificate untuk mengunduh informasi sertifikat. Setelah Anda mengekstraksi file sertifikat, ganti nilai parameter ini dengan informasi dalam file
.keydalam format nilai contoh.Kunci privat terdiri dari beberapa baris string. Elipsis (...) dalam kode sampel menunjukkan string yang dihilangkan. Tambahkan
"di awal dan\r\n"di akhir setiap string.host x509.itls.cn-shanghai.aliyuncs.com Format: x509.itls.${YourRegionId}.aliyuncs.com.Ganti ${YourRegionId} dengan ID wilayah tempat perangkat terhubung ke IoT Platform. Untuk informasi lebih lanjut, lihat Wilayah dan zona.
port 1883 Nomor port. product_key "" Jika Anda menggunakan sertifikat X.509 untuk otentikasi, tentukan string kosong untuk masing-masing parameter ini. device_name "" device_secret ""
- Konfigurasikan callback untuk mendapatkan informasi identitas perangkat.Setelah perangkat menggunakan Sertifikat X.509 untuk otentikasi dan menetapkan koneksi dengan IoT Platform, IoT Platform mengirimkan pesan yang berisi ProductKey dan DeviceName ke perangkat. Anda harus mengonfigurasi callback untuk menerima pesan tersebut. Callback dipanggil untuk menyimpan parameter ini ke lokasi tertentu untuk penggunaan selanjutnya.
Anda dapat menyesuaikan fungsi
demo_get_device_info. Dalam contoh ini, pesan diurai dan dicetak.static void demo_get_device_info(const char *topic, uint16_t topic_len, const char *payload, uint32_t payload_len) { const char *target_topic = "/ext/auth/identity/response"; char *p_product_key = NULL; uint32_t product_key_len = 0; char *p_device_name = NULL; uint32_t device_name_len = 0; int32_t res = STATE_SUCCESS; if (topic_len != strlen(target_topic) || memcmp(topic, target_topic, topic_len) != 0) { return; } /* TODO: Operasi core_json_value dalam SDK ditentukan sebagai contoh. Anda harus mengganti operasi tersebut dengan operasi dari pustaka parser JSON seperti cJSON untuk memproses payload. */ res = core_json_value(payload, payload_len, "productKey", strlen("productKey"), &p_product_key, &product_key_len); if (res < 0) { return; } res = core_json_value(payload, payload_len, "deviceName", strlen("deviceName"), &p_device_name, &device_name_len); if (res < 0) { return; } if (g_product_key == NULL) { g_product_key = malloc(product_key_len + 1); if (NULL == g_product_key) { return; } memset(g_product_key, 0, product_key_len + 1); memcpy(g_product_key, p_product_key, product_key_len); } if (g_device_name == NULL) { g_device_name = malloc(device_name_len + 1); if (NULL == g_product_key) { return; } memset(g_device_name, 0, device_name_len + 1); memcpy(g_device_name, p_device_name, device_name_len); } printf("device productKey: %s\r\n", g_product_key); printf("device deviceName: %s\r\n", g_device_name); }- Catatan:
IoT Platform menggunakan topik
/ext/auth/identity/responseuntuk mengeluarkan ProductKey dan DeviceName ke perangkat. FormatPayload:{ "productKey":"***", "deviceName":"***" }
Konfigurasikan callback untuk memantau status dan menerima pesan.
Konfigurasikan callback untuk memantau status.
Kode contoh:
int main(int argc, char *argv[]) { ... ... /* Tentukan callback default untuk menerima pesan MQTT. */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_RECV_HANDLER, (void *)demo_mqtt_default_recv_handler); /* Tentukan callback untuk menangani acara MQTT. */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_EVENT_HANDLER, (void *)demo_mqtt_event_handler); ... ... }Parameter:
Parameter
Contoh
Deskripsi
AIOT_MQTTOPT_RECV_HANDLER
demo_mqtt_default_recv_handler
Saat pesan diterima, callback dipanggil untuk melakukan operasi yang diperlukan.
AIOT_MQTTOPT_EVENT_HANDLER
demo_mqtt_event_handler
Jika status koneksi perangkat berubah, callback dipanggil untuk melakukan operasi yang diperlukan.
Definisikan callback untuk memantau status.
PentingJangan definisikan logika yang memakan waktu untuk memproses acara. Ini mencegah thread yang digunakan untuk menerima paket dari diblokir.
Perubahan status koneksi mencakup pengecualian jaringan, rekoneksi otomatis, dan pemutusan koneksi.
Untuk menangani perubahan status koneksi, Anda dapat memodifikasi kode di bagian
TODOberdasarkan kebutuhan bisnis Anda.
/* Callback untuk menangani acara MQTT. Jika koneksi dibuat, dipulihkan, atau ditutup, callback dipanggil. Untuk informasi tentang definisi acara, lihat core/aiot_mqtt_api.h. */ void demo_mqtt_event_handler(void *handle, const aiot_mqtt_event_t *event, void *userdata) { switch (event->type) { /* Panggil operasi aiot_mqtt_connect untuk menetapkan koneksi ke broker MQTT. */ case AIOT_MQTTEVT_CONNECT: { printf("AIOT_MQTTEVT_CONNECT\n"); /* TODO: Definisikan logika pemrosesan setelah koneksi antara SDK dan broker MQTT ditetapkan. Jangan panggil fungsi yang memakan waktu yang dapat memblokir thread. */ } break; /* Jika kesalahan pemutusan koneksi terjadi karena pengecualian jaringan, SDK secara otomatis memulai permintaan untuk menyambungkan kembali dengan broker MQTT. */ case AIOT_MQTTEVT_RECONNECT: { printf("AIOT_MQTTEVT_RECONNECT\n"); /* TODO: Definisikan logika pemrosesan setelah koneksi baru ditetapkan antara SDK dan broker MQTT. Jangan panggil fungsi yang memakan waktu yang dapat memblokir thread. */ } break; /* Kesalahan pemutusan koneksi terjadi karena pengecualian jaringan. Operasi baca atau tulis tingkat rendah gagal. Tanggapan heartbeat tidak diperoleh dari broker MQTT. */ case AIOT_MQTTEVT_DISCONNECT: { char *cause = (event->data.disconnect == AIOT_MQTTDISCONNEVT_NETWORK_DISCONNECT) ? ("network disconnect") : ("heartbeat disconnect"); printf("AIOT_MQTTEVT_DISCONNECT: %s\n", cause); /* TODO: Definisikan logika pemrosesan setelah SDK diputuskan secara pasif dari broker MQTT. Jangan panggil fungsi yang memakan waktu yang dapat memblokir thread. */ } break; default: { } } }Definisikan callback untuk menerima pesan.
PentingJangan definisikan logika yang memakan waktu untuk memproses acara. Ini mencegah thread yang digunakan untuk menerima paket dari diblokir.
Untuk memproses pesan yang diterima, Anda dapat memodifikasi kode di bagian
TODOberdasarkan kebutuhan bisnis Anda.
/* Callback default untuk memproses pesan MQTT. Jika SDK menerima pesan dari broker MQTT dan Anda tidak mengonfigurasi callback, operasi berikut dipanggil. */ void demo_mqtt_default_recv_handler(void *handle, const aiot_mqtt_recv_t *packet, void *userdata) { switch (packet->type) { case AIOT_MQTTRECV_HEARTBEAT_RESPONSE: { printf("heartbeat response\n"); /* TODO: Definisikan logika untuk memproses tanggapan heartbeat dari broker MQTT. Dalam banyak kasus, logika ini tidak diperlukan. */ } break; case AIOT_MQTTRECV_SUB_ACK: { printf("suback, res: -0x%04X, packet id: %d, max qos: %d\n", -packet->data.sub_ack.res, packet->data.sub_ack.packet_id, packet->data.sub_ack.max_qos); /* TODO: Definisikan logika untuk memproses tanggapan broker MQTT terhadap permintaan langganan. Dalam banyak kasus, logika ini tidak diperlukan. */ */ } break; case AIOT_MQTTRECV_PUB: { printf("pub, qos: %d, topic: %.*s\n", packet->data.pub.qos, packet->data.pub.topic_len, packet->data.pub.topic); printf("pub, payload: %.*s\n", packet->data.pub.payload_len, packet->data.pub.payload); /* TODO: Definisikan logika untuk memproses pesan bisnis yang dikirim oleh broker MQTT. */ } break; case AIOT_MQTTRECV_PUB_ACK: { printf("puback, packet id: %d\n", packet->data.pub_ack.packet_id); /* TODO: Definisikan logika untuk memproses tanggapan broker MQTT terhadap pesan QoS 1. Dalam banyak kasus, logika ini tidak diperlukan. */ } break; default: { } } }
Langkah 3: Tetapkan koneksi
Panggil operasi aiot_mqtt_connect untuk mengirim permintaan autentikasi dan koneksi ke IoT Platform.
/* Tetapkan koneksi MQTT dengan IoT Platform. */ */
res = aiot_mqtt_connect(mqtt_handle);
if (res < STATE_SUCCESS) {
/* Lepaskan sumber daya instance MQTT jika koneksi MQTT gagal ditetapkan. */
aiot_mqtt_deinit(&mqtt_handle);
printf("aiot_mqtt_connect gagal: -0x%04X\n", -res);
return -1;
}Langkah 4: Aktifkan thread keep-alive
Panggil operasi aiot_mqtt_process untuk mengirim pesan heartbeat ke broker MQTT dan mengirim ulang pesan QoS 1 yang tidak menghasilkan tanggapan. Dengan cara ini, koneksi persisten diaktifkan.
Aktifkan thread keep-alive.
res = pthread_create(&g_mqtt_process_thread, NULL, demo_mqtt_process_thread, mqtt_handle); if (res < 0) { printf("pthread_create demo_mqtt_process_thread gagal: %d\n", res); return -1; }Konfigurasikan fungsi untuk mengelola thread keep-alive.
void *demo_mqtt_process_thread(void *args) { int32_t res = STATE_SUCCESS; while (g_mqtt_process_thread_running) { res = aiot_mqtt_process(args); if (res == STATE_USER_INPUT_EXEC_DISABLED) { break; } sleep(1); } return NULL; }
Langkah 5: Aktifkan thread untuk menerima pesan
Panggil operasi aiot_mqtt_recv untuk menerima pesan MQTT dari broker. Operasi yang diperlukan dilakukan menggunakan callback untuk menerima pesan. Jika terjadi pemutusan koneksi dan kemudian rekoneksi otomatis, operasi yang diperlukan dilakukan menggunakan callback untuk menangani acara.
Aktifkan thread untuk menerima pesan.
res = pthread_create(&g_mqtt_recv_thread, NULL, demo_mqtt_recv_thread, mqtt_handle); if (res < 0) { printf("pthread_create demo_mqtt_recv_thread gagal: %d\n", res); return -1; }Konfigurasikan fungsi untuk mengelola thread.
void *demo_mqtt_recv_thread(void *args) { int32_t res = STATE_SUCCESS; while (g_mqtt_recv_thread_running) { res = aiot_mqtt_recv(args); if (res < STATE_SUCCESS) { if (res == STATE_USER_INPUT_EXEC_DISABLED) { break; } sleep(1); } } return NULL; }
Langkah 6: Berlangganan topik
Panggil operasi aiot_mqtt_sub untuk berlangganan topik tertentu.
Kode contoh:
{ char *sub_topic = "/a18wP******/LightSwitch/user/get"; res = aiot_mqtt_sub(mqtt_handle, sub_topic, NULL, 1, NULL); if (res < 0) { printf("aiot_mqtt_sub gagal, res: -0x%04X\n", -res); return -1; } }CatatanSetelah Anda mengonfigurasi kode contoh, hapus simbol anotasi di kedua sisi kode.
Parameter:
Parameter
Contoh
Deskripsi
sub_topic
/a18wP******/LightSwitch/user/get
Topik tempat perangkat memiliki izin Subscribe.
a1oGs******adalah ProductKey dari perangkat.LightSwitchadalah DeviceName dari perangkat.
Dalam contoh ini, topik kustom default digunakan.
Perangkat dapat menerima pesan dari IoT Platform melalui topik ini.
Untuk informasi lebih lanjut, lihat Topik.
Langkah 7: Kirim pesan
Panggil operasi aiot_mqtt_pub untuk mengirim pesan ke topik tertentu.
Kode contoh:
{ char *pub_topic = "/a18wP******/LightSwitch/user/update"; char *pub_payload = "{\"id\":\"1\",\"version\":\"1.0\",\"params\":{\"LightSwitch\":0}}"; res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)pub_payload, (uint32_t)strlen(pub_payload), 0); if (res < 0) { printf("aiot_mqtt_sub gagal, res: -0x%04X\n", -res); return -1; } }CatatanSetelah Anda mengonfigurasi kode contoh, hapus simbol anotasi di kedua sisi kode.
Parameter:
Parameter
Contoh
Deskripsi
pub_topic
/a18wP******/LightSwitch/user/update
Topik tempat perangkat memiliki izin Publish.
a1oGs******adalah ProductKey dari perangkat.LightSwitchadalah DeviceName dari perangkat.
Perangkat mengirim pesan ke IoT Platform melalui topik ini.
Untuk informasi lebih lanjut, lihat Topik.
pub_payload
{\"id\":\"1\",\"version\":\"1.0\",\"params\":{\"LightSwitch\":0}}
Isi pesan yang ingin Anda kirimkan oleh perangkat ke IoT Platform.
Dalam contoh ini, topik kustom digunakan. Anda dapat menentukan format pesan kustom.
Untuk informasi lebih lanjut, lihat Format data.
Setelah koneksi MQTT antara perangkat dan IoT Platform ditetapkan, pastikan jumlah pesan tidak melebihi ambang batas.
Untuk informasi lebih lanjut tentang batasan komunikasi, lihat Batasan.
Jika jumlah pesan melebihi ambang batas, masuk ke konsol IoT Platform untuk melihat pesan yang terakumulasi. Untuk informasi lebih lanjut, lihat Lihat dan Pantau Grup Konsumen.
Langkah 8: Putuskan koneksi perangkat dari IoT Platform
Koneksi MQTT diterapkan pada perangkat yang tetap terhubung secara persisten. Anda dapat memutuskan koneksi perangkat dari IoT Platform secara manual.
Dalam contoh ini, thread utama digunakan untuk mengonfigurasi parameter dan menetapkan koneksi. Setelah koneksi ditetapkan, Anda dapat menangguhkan thread utama.
Panggil operasi aiot_mqtt_disconnect untuk memutuskan koneksi perangkat dari IoT Platform.
res = aiot_mqtt_disconnect(mqtt_handle);
if (res < STATE_SUCCESS) {
aiot_mqtt_deinit(&mqtt_handle);
printf("aiot_mqtt_disconnect gagal: -0x%04X\n", -res);
return -1;
}Langkah 9: Keluar dari program
Panggil operasi aiot_mqtt_deinit untuk menghapus instance klien MQTT dan melepaskan sumber daya.
res = aiot_mqtt_deinit(&mqtt_handle);
if (res < STATE_SUCCESS) {
printf("aiot_mqtt_deinit gagal: -0x%04X\n", -res);
return -1;
}Apa yang harus dilakukan selanjutnya
Dalam contoh ini, file eksekusi
./output/mqtt-x509-auth-demodihasilkan.Untuk informasi lebih lanjut, lihat Persiapkan Lingkungan.