最近測試廣州電信的電話會議平臺,該平臺接入採用HTTPS協議,因而有了本文。09年培訓時寫過一個簡單的TLS C/S結構交互,採用openssl的ssl相關接口,但與生產相去勝遠。本文采用openssl提供的BIO。html
長連接仍是短連接?c++
測試過程當中發現長鏈接在一段時間內沒有數據交互會被服務方釋放,沒法從新鏈接。根據自身業務選擇。函數
BIO設置爲阻塞仍是非阻塞?性能
本場景下都爲http同步請求,故設置爲阻塞。代碼實現時必須考慮阻塞的等待時間(測試結果是默認阻塞BIO爲60s超時)對性能和業務的影響。測試
讀寫出錯控制code
若是寫出錯,須要校驗BIO_should_retry,若是爲true,需等待片刻後從新寫,阻塞的BIO通常不會出現;htm
若是讀出錯,一樣要校驗BIO_should_retry,非阻塞的BIO可能會影響性能。接口
相關頭文件:ssl
#include <openssl/bio.h> #include <openssl/ssl.h> #include <openssl/err.h> /* Initializing OpenSSL */ SSL_library_init(); SSL_load_error_strings(); ERR_load_BIO_strings(); OpenSSL_add_all_algorithms(); SSL_CTX *m_ctx =SSL_CTX_new(SSLv23_client_method()); if (m_ctx == NULL) { exit(1); } //加載pem 該pem是openssl源碼庫裏自帶的 if(! SSL_CTX_load_verify_locations(m_ctx, "./certs/demo/ca-cert.pem", NULL)) { exit(1); }
下面四個函數封裝了BIO的建立、釋放、讀和寫,能夠知足基本的需求了。get
BIO * bio_new () { SSL *ssl; BIO *bio = BIO_new_ssl_connect (m_ctx); BIO_get_ssl (bio, & ssl); if (!ssl) { BIO_free_all (bio); return NULL; } SSL_set_mode (ssl, SSL_MODE_AUTO_RETRY); //自動重試 BIO_set_conn_hostname (bio, "xxx.com:443"); if (BIO_do_connect (bio) & lt; = 0) { BIO_free_all (bio); return NULL; } //校驗失敗是非致命的 if (SSL_get_verify_result (ssl) != X509_V_OK) { /* Handle the failed verification */ } if (BIO_do_handshake (bio) & lt; = 0) { //ssl握手 BIO_free_all (bio); return NULL; } return bio; } int bio_write (BIO * bio, const char *buf, int len) { if (buf == NULL) { return PROC_FAILED; } if (BIO_write (bio, buf, len) & lt; = 0) { if (!BIO_should_retry (bio)) { /* Handle failed write here */ return PROC_FAILED; } /* Do something to handle the retry */ return PROC_FAILED; } return PROC_SUCCESS; } int bio_read (BIO * bio, char *buf, int len) { if (buf == NULL) { return PROC_FAILED; } int x = BIO_read (bio, buf, len); if (x == 0) { /* Handle closed connection */ return PROC_FAILED; } else if (x & lt; 0) { if (!BIO_should_retry (bio)) { /* Handle failed read here */ return PROC_FAILED; } /* Do something to handle the retry */ return PROC_FAILED; } return x; } int bio_close (BIO * bio) { if (bio != NULL) BIO_free_all (bio); return PROC_SUCCESS; } BIO * bio = bio_new (); if (bio == NULL) { return PROC_FAILED; } //發送數據 if (bio_write (bio, buff, strlen (buff)) == PROC_FAILED) { bio_close (bio); return PROC_FAILED; } char response[8192] = { 0x00 }; int len = 0; //接收數據 if ((len = bio_read (bio, response, 8192)) == PROC_FAILED) { bio_close (bio); return PROC_FAILED; } bio_close (bio);
參考資料:
https://www.openssl.org/docs/crypto/BIO_f_ssl.html
https://www.openssl.org/docs/crypto/BIO_should_retry.html
另:BIO也不少種類型,感受功能很強大,本人c++菜鳥,沒仔細研究...