【问题标题】:Is it okay to change socket from non-blocking to blocking and then non-blocking again?可以将套接字从非阻塞更改为阻塞然后再次非阻塞吗?
【发布时间】:2015-11-27 18:12:34
【问题描述】:

我的应用程序的整个逻辑都使用非阻塞套接字,但在连接阶段,我发现在与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 使用率较低。谢谢。

【问题讨论】:

  • 改变socket的状态没有错。但是为什么不正确地握手而不阻塞呢?如果SSL_connect 会阻塞,请调用SSL_get_error 并正确处理SSL_ERROR_WANT_READSSL_ERROR_WANT_WRITE
  • 这样做会导致我试图避免的繁忙循环。
  • 不,它不会,出于同样的原因,您的读写不会导致繁忙的循环。 SSL_connectSSL_read 一样工作。 See here.
  • 读取确实会导致繁忙的循环,因此每次收到 EWOULDBLOCK 或 SSL_WANT_READ / WRITE 时,我都必须让线程休眠几微秒。
  • 哦,那你问错问题了。你根本不明白如何进行非阻塞套接字操作。

标签: c++ linux sockets openssl


【解决方案1】:

这似乎是一个 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-19
    • 2010-10-31
    • 2013-10-15
    • 1970-01-01
    • 2017-04-18
    • 2023-03-19
    • 2012-10-31
    相关资源
    最近更新 更多