与OpenSSL的多线程通信

fiz*_*ixx 5 c++ multithreading openssl

我正在使用OpenSSL与服务器通信.我可以随时向服务器发送数据,服务器可能会也可能不会发回响应.服务器还可以在没有请求的情况下将数据发送到客户端.

我在使用BIO_new_ssl_connect制作的BIO上使用SSL,然后使用SSL_read和SSL_write.

我的第一种方法是使用阻塞套接字.我会启动一个线程并在循环中调用SSL_read.每个调用都会阻塞,并且仅在读取某些数据时返回.每次调用后,我都可以打包数据并将其发送到某个地方.当我必须编写时,我只是从另一个线程调用SSL_write.

我无法弄清楚在从不同线程的同一连接上执行SSL_read时调用SSL_write是否有效.当我尝试断开连接(SSL_free/BIO_free)时,SSL_read调用崩溃.

来自不同线程的这些调用是否可取?如果没有,是否有更好的方法解决这个问题(这似乎是一个非常普遍的事情)?

非阻塞插座可能会更好吗?

编辑:对不起,我应该补充一点,我已经实现了OpenSSL文档中描述的线程安全锁定.

jxh*_*jxh 8

OpenSSL库可以是线程安全的,但您必须自己提供锁定原语.从OpenSSL FAQ:

多线程应用程序必须通过调用提供两个回调函数的OpenSSL CRYPTO_set_locking_callback()CRYPTO_set_id_callback(),高达和包括0.9.8 [ABC ...]的OpenSSL的所有版本.从版本1.0.0开始,CRYPTO_set_id_callback()相关的API被CRYPTO_THREADID_set_callback()朋友们弃用.这在手册threads(3)页中进行了描述.

关于SSL_free()在另一个线程被阻止时进行调用SSL_read(),请不要这样做.如果库是线程安全的,那就是API违规也没关系.同时SSL_read()SSL_write()从单独的线程是好的.如果另一个线程仍在使用SSL_CTX *,则线程将需要相互协作以确定何时可以安全地调用SSL_free(),因为允许另一个线程读取或写入释放的内存是错误的.毕竟,OpenSSL是一个库,SSL_CTX *它只是从堆中分配的普通结构.

您通常使用引用计数跟踪何时可以安全地释放对象.如果您不想在应用程序代码本身中管理它们,则可以将引用计数隐藏在自定义BIO中.

您提到使用非阻塞模式的可能性.这本身不足以解决您的内存管理错误.您仍需要引用计数来确定是否可以安全地呼叫SSL_free().

顺便说一句,如果您决定使用非阻塞模式,您可能应该将非阻塞模式与多线程结合使用,以便最大化多核系统上的CPU利用率.但是,非阻塞OpenSSL实际上比常规非阻塞BSD套接字复杂一个数量级.这是因为除了读取或写入时常规的"阻塞"之外,OpenSSL读取可能会报告它需要写操作才能完成,而OpenSSL写入可能会报告它需要读取操作才能完成.因此,您的非阻塞代码需要记住在处理来自多路分解器的完成通知后所尝试的操作(例如,选择或轮询).此外,OpenSSL规定您必须传入与"阻止"通知返回时尝试的完全相同的参数.因此,作为一个示例,您可能实际要发送的任何新数据都必须进行缓冲,直到当前的OpenSSL写入完成.