最近测试广州电信的电话会议平台,该平台接入采用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++菜鸟,没仔细研究...