我正在处理一个项目,该项目需要通过安全套接字连接连接到服务器并发送一些命令,以防其中一个命令失败,我在该套接字上得到错误响应,然后套接字关闭。
我尝试过使用非阻塞ssl套接字的单线程方法。我连接到服务器然后发送一些命令,对错误状态执行非阻塞读取,发送更多命令,再次读取等等。该服务器是Apple推送通知服务,以防万一。
一切似乎都没问题,直到我收到错误响应,然后服务器关闭套接字。我可以读取错误响应并看到套接字已关闭,但是当我释放BIO对象时,应用程序崩溃(未处理的SIGPIPE)。在我看来它崩溃了,因为即使在套接字关闭后我也可能正在发送数据。这是发出SIGPIPE信号后的回溯:
queue = 'com.apple.main-thread', stop reason = signal SIGPIPE
frame #0: 0x94cad46a libsystem_kernel.dylib`__write + 10
frame #1: 0x0007b835 APNTest`conn_write + 69
frame #2: 0x0007957d APNTest`BIO_write + 141
frame #3: 0x00100127 APNTest`ssl3_write_pending + 215
frame #4: 0x001001f9 APNTest`do_ssl3_write + 57
frame #5: 0x00101cab APNTest`ssl3_dispatch_alert + 59
frame #6: 0x000fdb80 APNTest`ssl3_shutdown + 112
frame #7: 0x00126e43 APNTest`ssl_ctrl + 83
frame #8: 0x00005653 APNTest`APNConnection::shutdown(this=0x00300fd0) + 83 at APNConnection.cpp:136
frame #9: 0x000055e5 APNTest`APNConnection::~APNConnection(this=0x00300fd0) + 21 at APNConnection.cpp:41
frame #10: 0x00005687 APNTest`APNConnection::~APNConnection(this=0x00300fd0) + 23 at APNConnection.cpp:40
frame #11: 0x000024d6 APNTest`APNService::run(this=0xbffff7a8) + 1190 at APNService.cpp:73
frame #12: 0x00006a6a APNTest`main + 1946 at main.cpp:36
frame #13: 0x94ce46d9 libdyld.dylib`start + 1
以下是我用来创建OpenSSL安全套接字的代码
BIO *bio;
SSL_CTX *ctx;
SSL *ssl;
ctx = SSL_CTX_new(SSLv23_client_method());
if (!SSL_CTX_load_verify_locations(ctx, strdup(trustStoreFile.c_str()), NULL)) {...}
if (SSL_CTX_use_certificate_file(ctx, strdup(clientCertFile.c_str()), SSL_FILETYPE_PEM) <= 0) {...}
if (SSL_CTX_use_PrivateKey_file(ctx, strdup(clientPKFile.c_str()), SSL_FILETYPE_PEM) <= 0) {...}
bio = BIO_new_ssl_connect(ctx);
BIO_get_ssl(bio, & ssl);
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
BIO_set_nbio(bio, 1);
BIO_set_conn_hostname(bio, serverURL.c_str());
int connErr = 0;
do {
connErr = BIO_do_connect(bio);
} while (BIO_should_retry(bio));
使用BIO_write(bio, data, size)
和BIO_read(bio, data, datasize)
清理代码和崩溃的代码
SSL_CTX_free(ctx);
BIO_reset(bio);
BIO_free_all(bio);
BIO_reset是现在崩溃的那个,但是如果我将其删除,BIO_free_all将崩溃。我可以做的是避免崩溃,一次发送一个命令,每次命令发送后我应该等待1秒左右,看看服务器是否发送了该命令的错误,再发送一个,再等一下等等上。或者帮助我隐藏崩溃的另一件事是为SIGPIPE安装一个虚拟信号处理程序,但这些只是解决方法。
我猜测它可能会因为在套接字关闭后排队等待发送的数据而崩溃。是什么让我相信这是因为我看到ssl3_shutdown调用了一些ssl3_write_pending,并且因为在我得到非零SSL_shutdown()之后我特别小心不再做BIO_write,所以清理代码也不会崩溃。
我是否在清理代码时出错了?还是有办法指示OpenSSL在释放BIO和SSL对象时丢弃任何数据?
感谢您的帮助!