可以将socket从非阻塞更改为阻塞,然后再次更改为非阻塞吗?
Is it okay to change socket from non-blocking to blocking and then non-blocking again?
我的应用程序的整个逻辑与非阻塞套接字一起工作,但在连接阶段,我发现在与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秒尝试重新连接一次,并且用户偶尔会得到小于15秒的CPU峰值。
Edit:我在这个问题上得到的答案让我看到如何尝试读取非阻塞套接字,然后睡觉并不是一个好主意。然而,我确实需要一个独立于平台的poll
解决方案,所以我已经继续并添加了一个select
,在读取操作上有15秒超时,在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
等待套接字变为可读/可写。如果出现超时或错误,请适当地处理它。如果socket变为可读/可写,则再次调用SSL_connect
。
您应该以相同的方式处理SSL_read
和SSL_write
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 这是我尝试让用户将值输入到数组中.然后将其隐藏为大量的星号
- boost::asio如何生成多个协同程序,然后加入它们
- 如何将图像传输到c++(dll)中的缓冲区,然后在c#的缓冲区中读/写
- 在std::thread中,joinable()然后join()线程安全吗
- C++:如何读取分离变量,然后读取向量
- 为什么我的递归函数按降序打印,然后按升序打印?
- 等待整个 omp 块完成,然后再调用第二个函数
- CMake:如何将库 A 链接到库 B,然后将可执行文件链接到库 A
- 如何存储用户输入的所有数据,然后在他们想要查看所有数据时显示它们
- '{'标记之前的预期类名,然后在预声明时无效使用不完整的类型'class class_name'
- 如何使变量从 x 到 y,然后从 y 返回到 x 并始终重复该过程
- 我有一个数组,我想输入一个范围,然后找到范围内所有偶数的总和?
- 如何正确地推回然后遍历堆中对象的向量?
- 我似乎无法为指针分配一个数组,然后更改数组的内容
- C/C++:socket() 创建在循环中失败,打开的文件太多
- 如何在字符串中找到字符,然后在C++中提取其余的字符串
- 首先按给定顺序打印所有数字,然后使用 Array 打印所有字符和其他符号
- 可以将socket从非阻塞更改为阻塞,然后再次更改为非阻塞吗?