我的应用程序的整个逻辑都使用非阻塞套接字,但在连接阶段,我发现在使用 SSL_connect()
执行 SSL 握手之前,最好让套接字阻塞。这是因为否则它会创建一个繁忙的循环,直到握手成功完成,并且在此之前实际上阻塞套接字应该更有效。
这是我的连接逻辑的伪代码:
bool connect(host)
{
int socket;
init_socket(socket);
set (socket, NONBLOCKING);
connect_with_timeout(socket, host, 2s);
if (timeout_failed || connect_errors) return false;
set (socket, BLOCKING);
SSL_connect (socket);
if (ssl_connect_errors) return false;
set (socket, NONBLOCKING);
return true;
}
非阻塞套接字上的 SSL 握手如下所示:
do
{
SSL_connect(socket);
}
while (!SSL_connection_errors);
像这样更改套接字类型是否被认为是一种不好的做法?当您这样做时,在低级别上到底发生了什么?
我知道这似乎是性能上的微小改进,但我想把它做好,因为我的应用程序可能每 30 秒尝试重新连接一次,用户偶尔会遇到不到 1 秒的大 CPU 峰值。
编辑:我在这个问题上得到的答案让我明白尝试在非阻塞套接字上读取然后休眠并不是一个好主意。但是,我确实需要一个独立于平台的poll
解决方案,所以我已经继续添加了一个select
,读取操作超时为 1s,并针对 Windows 和 Linux 进行了测试, CPU 使用率现在较低。谢谢。
最佳答案
看来这是一个 XY 问题。您真正的问题是您不了解如何进行非阻塞套接字操作。对于 OpenSSL,当非阻塞操作被阻塞时,您应该调用 SSL_get_error
。如果错误是 SSL_ERROR_WANT_READ
,您应该在套接字可读时重试该操作。如果错误是 SSL_ERROR_WANT_WRITE
,您应该在套接字可写时重试该操作。
下一个问题是——如何等待套接字变为可读或可写?这取决于你的平台。对于 Linux,您可以使用 poll ,这也需要超时,因此您可以控制等待的时间。
保持套接字非阻塞。调用 SSL_connect
。如果调用被阻止,调用 SSL_get_error
,您将得到 SSL_ERROR_WANT_READ
或 SSL_ERROR_WANT_WRITE
。使用 poll
等待套接字变为可读/可写。如果出现超时或错误,请适当处理。如果套接字变为可读/可写,再次调用 SSL_connect
。
您应该以相同的方式处理 SSL_read
和 SSL_write
。
关于c++ - 可以将套接字从非阻塞更改为阻塞然后再次非阻塞吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32349715/