【问题标题】:Non-blocking connect OpenSSL非阻塞连接 OpenSSL
【发布时间】:2014-06-07 14:33:06
【问题描述】:

我创建了一个常规的 C 套接字。连接后,它按预期返回EWOULDBLOCK/WSAEWOULDBLOCK,因为我这样做了:

unsigned long int mode = 0;
ioctlsocket(ssl_info->sock, FIONBIO, &mode);
setsockopt(ssl_info->sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv));
setsockopt(ssl_info->sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv));

将套接字置于非阻塞模式。之后我会这样做:

ssl = SSL_new(ctx);
SSL_set_fd(ssl, sock);
return SSL_connect(ssl);

但是,它返回 -1。

我在网上看到这意味着我需要处理SSL_ERROR_WANT_READSSL_ERROR_WANT_WRITE

所以我做到了:

int res = -1;
while(res == -1)
{
    res = SSL_connect(ssl);
    switch (SSL_get_error(ssl, res))
    {
        case SSL_ERROR_WANT_CONNECT:
        MessageBox(NULL, "Connect Error", "", 0);
        break;

        case SSL_ERROR_WANT_READ:   //prints this every time..
        MessageBox(NULL, "Read Error", "", 0);
        break;

        case SSL_ERROR_WANT_WRITE:
        MessageBox(NULL, "Write Error", "", 0);
        break;
    }

    SelectSocket(ssl);
}

std::cout<<"Connected!\n";

其中SelectSocket定义为:

bool SelectSocket(SSL* ssl)
{
    if (blockmode)
    {
        fd_set readfds;
        fd_set writefds;
        FD_ZERO(&readfds);
        FD_ZERO (&writefds);
        FD_SET(ssl_info->sock, &readfds);
        FD_SET(ssl_info->sock, &writefds);

        struct timeval tv = {0};
        tv.tv_sec = timeout / 1000;
        tv.tv_usec = timeout % 1000;
        return select(sock + 1, &readfds, &writefds, NULL, &tv) >= 0;
    }

    return select(sock + 1, NULL, NULL, NULL, NULL) != SOCKET_ERROR;
}

那么我究竟怎样才能让它连接起来呢?当套接字非阻塞时,我似乎无法读取或写入任何内容:S.

有什么想法吗?

【问题讨论】:

  • 在非阻塞套接字上设置发送或接收超时没有意义。您确实需要处理 WANT_READ 和 WANT_WRITE。我建议你这样做。
  • 您的函数 SelectSocket 返回 bool,但您将其与 -1 进行比较 - 这可能不太好
  • 好的,我修复了 -1 的问题。还是一样。我不确定处理 WANT_READWANT_WRITE 的文档意味着什么。我尝试在无限循环中执行SSL_read;没有区别。
  • @Brandon,您提到 SSL_connect() 返回 (-1)。我假设您的代码随后称为 SSL_get_error()? (我在提供的代码中没有看到)。如果是,SSL_get_error() 返回了什么?
  • 我将代码添加到 OP。

标签: c++ c sockets openssl


【解决方案1】:

SSL_connect() 返回的 (-1) 表示底层 BIO 无法满足 SSL_connect() 继续握手的需要。

一般来说,调用进程必须在采取适当的行动后重复调用以满足 SSL_connect() 的需要。

但是,当使用非阻塞套接字时,什么都不做;但 select() 可用于检查所需条件。

(当使用缓冲 BIO 时,如 BIO 对,数据必须先写入 BIO 或从 BIO 中取出,然后才能继续。)

【讨论】:

【解决方案2】:

您的代码实际上禁用非阻塞 I/O。当您将 0 作为 FIONBIO 的参数值传递给 ioctlsocket 时,记录为:

飞安生物

*argp 参数是一个指向无符号长整型值的指针。如果 非阻塞模式 应该启用,则将 *argp 设置为 非零值,或者如果非阻塞模式应该启用,则将 *argp 设置为 禁用。 [..]

https://msdn.microsoft.com/en-us/library/windows/desktop/ms738573%28v=vs.85%29.aspx

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-16
    • 1970-01-01
    • 1970-01-01
    • 2017-04-18
    • 1970-01-01
    • 2015-09-19
    • 2013-07-20
    • 1970-01-01
    相关资源
    最近更新 更多