如何使用C實現MQTT+TLS客戶端程序(2)--實現MQTT Client

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船票:
https://github.com/ptonlix/MQTTWithTLS

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章