作者:ptonlix
來源:CSDN
原文:https://blog.csdn.net/ptonlix/article/details/79869756
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!
本人轉載。
mosquitto_pub&mosquitto_sub
在實現MQTT client之前,我們可以先使用mosquitto_pub和mosquitto_sub模擬,MQTT的發布和訂閱
打開三個終端,分別作為:
MQTT服務器,訂閱者,發布者
MQTT服務器
mosquitto -c mosquitto.conf
運行服務
訂閱
mosquitto_sub -t mtopic -u sub_client -P 123456 -v --cafile cacert.pem --cert client.crt --key client.key -p 8883 --tls-version tlsv1.2 --insecure
–cafile:加載ca證書的路徑,后面以此類推
上圖所示,連接成功的情況。
發布
mosquitto_pub -t mtopic -u pub_client -P 123456 -m "test" --cafile cacert.pem --cert client.crt --key client.key -p 8883 --tls-version tlsv1.2 --insecure
如上圖所示,消息發布成功,然后訂閱也成功,主題為mtopic,消息是test
使用C語言實現MQTT Client
這里我使用了兩個開源庫,libemqtt和mbedtls,感謝這兩個開源庫的作者,感謝開源~
https://github.com/menudoproblema/libemqtt.git
https://github.com/ARMmbed/mbedtls.git
代碼分析
初始化操作
/*
* 0. Initialize the RNG and the session data
*/
mbedtls_net_init( &server_fd );
mbedtls_ssl_init( &ssl );
mbedtls_ssl_config_init( &conf );
mbedtls_x509_crt_init( &cacert );
mbedtls_x509_crt_init( &clicert );
mbedtls_pk_init( &pkey );
mbedtls_ctr_drbg_init( &ctr_drbg );
mbedtls_printf( "\n . Seeding the random number generator..." );
fflush( stdout );
mbedtls_entropy_init( &entropy );
if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
(const unsigned char *) pers,
strlen( pers ) ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret );
goto exit;
}
mbedtls_printf( " ok\n" );
加載證書
ret = mbedtls_x509_crt_parse_file( &cacert, "./cacert.pem");
if( ret < 0 )
{
mbedtls_printf( " failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret );
goto exit;
}
mbedtls_printf( " ok (%d skipped)\n", ret );
ret = mbedtls_x509_crt_parse_file( &clicert, "./client.crt");
if( ret != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_x509_crt_parse returned %d\n\n", ret );
goto exit;
}
ret = mbedtls_pk_parse_keyfile( &pkey, "./client.key", "123456");
if( ret != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_pk_parse_key returned %d\n\n", ret );
goto exit;
}
mbedtls_pk_parse_keyfile 第三個參數是生成客戶端證書,自己輸入的密鑰
建立TCP連接
/*
* 1. Start the connection
*/
mbedtls_printf( " . Connecting to tcp/%s/%s...", SERVER_NAME, SERVER_PORT );
fflush( stdout );
if( ( ret = mbedtls_net_connect( &server_fd, SERVER_NAME,
SERVER_PORT, MBEDTLS_NET_PROTO_TCP ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_net_connect returned %d\n\n", ret );
goto exit;
}
TLS握手
/*
* 4. Handshake
*/
mbedtls_printf( " . Performing the SSL/TLS handshake..." );
fflush( stdout );
while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 )
{
if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", -ret );
goto exit;
}
}
mbedtls_printf( " ok\n" );
握手階段結束,就完成了TLS連接,開始加密通訊,下面就是應用層MQTT的連接
MQTT連接
mbedtls_printf(" \n.....................mqtttenter.....................\n" );
PTmqtttenter();
mqtt_connect((mqtt_broker_handle_t *)PTMqttGetBroker());
mbedtls_printf( "\n....................mqtt_connect.....................\n" );
mqtt_subscribe((mqtt_broker_handle_t *)PTMqttGetBroker(), MQTTSUBTOPIC, 0);
mqtt_publish((mqtt_broker_handle_t *)PTMqttGetBroker(), MQTTPUBTOPIC, test, strlen(test), 0);
這樣就完成MQTT的連接,我們來看下實際效果
如上圖,我發送的MQTT消息,主題為mtopic 消息為test_cfd
訂閱的終端,可以成功收到消息。
注意:程序運行加載的證書是在工程目錄下,并且需要各位根據自己生成的客戶端證書進行相應的替換。
github link
最后附上,本工程的github船票:
https://github.com/ptonlix/MQTTWithTLS