我知道 OpenSSL API 中禁止从同一 SSL
上下文中的两个不同线程调用 SSL_read
和 SSL_write
,但它是在我的应用程序中,安全的全双工通信很重要。我想到了一些解决方案,但没有一个是我真正喜欢的:
- 每个连接使用两个
SSL
上下文。我不喜欢这样做,因为它使用更多资源,并且会使我的实现变得复杂。不过,如果我可以“复制”现有的SSL
上下文而不是从头开始创建一个全新的连接,那么我会很好地使用它。 - 使用带有互斥锁的非阻塞套接字来控制对
SSL
上下文的访问。这需要占用资源的轮询,而且我听说非阻塞实现不太好。
这似乎是一件相当常见的事情,那么这个问题的公认解决方案是什么?
最佳答案
Use non-blocking sockets with a mutex controlling access to an SSL context.
使用单线程内的非阻塞套接字,您将不需要互斥体,因为您只能读取或写入(因为单线程)。
This would require resource-hogging polling, ...
您不需要“占用资源”轮询。我假设您在这里指的是忙轮询,而不是使用系统的常用功能(例如 select
)来等待(而不是循环)直到数据可用或可以发送数据。但与普通套接字上的读/写相反,SSL 套接字如果想写则需要读,如果想读则需要写,并且即使套接字不可读,内部也可能有数据。请留意 SSL_WANT_READ
、SSL_WANT_WRITE
和 SSL_pending
。
...and I heard the non-blocking implementation is just not very good.
如果您习惯使用线程,它看起来会更复杂。但是你有没有想过为什么像 nginx 这样的高性能服务器不使用线程而是使用非阻塞 I/O?这是因为它需要更少的资源,并且没有与线程相关的问题,例如需要在关键部分(开销)周围进行互斥,并且在忘记互斥某些内容时会出现奇怪和零星的错误。 nginx 还使用具有非阻塞 I/O 的 openssl。
我个人一直使用非阻塞 I/O,虽然由于协议(protocol)本身而不是 OpenSSL 实现而很难正确使用 SSL,但它是可行且快速的。
这意味着,单线程内的非阻塞 I/O 是解决问题的一种方法。另一种方法是让 SSL 只与内存 BIO 一起工作,而不是真正的文件描述符,并自行完成所有读写操作。但这可能比非阻塞 I/O 更复杂。
顺便说一句,通常SSL上下文表示可以在多个SSL连接之间共享的SSL_CTX
对象,并且对于多线程来说可能没有问题。您的意思是,不应从多个线程使用同一个 SSL 连接(SSL
对象)。
关于multithreading - 来自多个线程的 OpenSSL SSL_read 和 SSL_write,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25392494/