是否可以将套接字从非阻塞更改为阻止,然后再次无阻塞?

时间:2015-09-02 09:40:12

标签: c++ linux sockets openssl

我的应用程序的整个逻辑适用于非阻塞套接字,但在连接阶段,我发现在使用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,读取操作超时1秒,对Windows和Linux进行了测试,现在CPU使用率较低。谢谢。

1 个答案:

答案 0 :(得分:4)

看来这是一个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等待套接字变为可读/可写。如果出现超时或错误,请正确处理。如果套接字变得可读/可写,请再次致电SSL_connect

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