可以将socket从非阻塞更改为阻塞,然后再次更改为非阻塞吗?

Is it okay to change socket from non-blocking to blocking and then non-blocking again?

本文关键字:然后 socket      更新时间:2023-10-16

我的应用程序的整个逻辑与非阻塞套接字一起工作,但在连接阶段,我发现在与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_READSSL_ERROR_WANT_WRITE。使用poll等待套接字变为可读/可写。如果出现超时或错误,请适当地处理它。如果socket变为可读/可写,则再次调用SSL_connect

您应该以相同的方式处理SSL_readSSL_write

相关文章: