如何判断何时无法在SSL连接上取得进展

时间:2013-01-17 11:36:00

标签: openssl nonblocking

下面

http://marc.info/?l=openssl-users&m=124386218929227

它声明

“......这就是为什么理解任何端口上的任何可能的正向进展(以及返回WANT_READ的写操作可能已经取得进展!)都非常重要,这要求您重试所有端口上的所有挂起操作。 ......“

因此,我理解返回SSL_read()的{​​{1}}可能已取得进展(即使它没有返回任何数据),我是否正确?

我有一个事件驱动的单线程应用程序,它有3个非阻塞的ssl套接字。当每个套接字完成连接时,我会读取套接字,直到我得到WANT_READ。我的理解是WANT_READ意味着我现在可以调用WANT_READ并等待套接字再次准备好再次阅读。

select()返回时,一个循环遍历3个套接字,每个套接字调用select()

说Socket 1上的读取返回ssl_read()而没有数据。 是否有可能Socket 2返回一些数据,当没有更多内容可以读取时返回WANT_READ,现在已经取得了一些进展,因此套接字1上的读取现在可以返回数据?但由于循环已经完成了对套接字1的读取,因此不会发生。

当循环通过3个插槽时,它会在那里等待并挂起。这种情况会发生吗?

如果是这种情况,如何查看是否所有3个插座都无法取得进展? 例如,假设循环通过;

  • 套接字1返回WANT_READ
  • socket 2返回一些数据,然后WANT_READ(并取得进展,使套接字1现在可以返回数据)
  • 套接字3返回WANT_READ

但基于上面的引用(任何前进进度需要重试所有挂起的操作),我应该再次重试所有套接字;所以第二次贯穿循环;

  • 套接字1现在返回数据,然后是WANT_READ
  • 套接字2返回WANT_READ
  • socket 3现在返回数据(因为套接字1上的读取使套接字3有足够的进度来返回数据),然后是WANT_READ

但是如果套接字3上的最后一次读取取得了进展,那么套接字2现在又会返回数据呢?所以我的问题是(如果我的理解是正确的),我怎么知道是否不能再取得进展呢?

编辑1:

所以我看到的是:

我的循环遍历连接到client1的所有套接字(例如,有2个套接字)

  • 套接字1:WANT_READ返回WANT_READ
  • socket 2:ssl_read()返回数据,ssl_read()再次返回数据,然后ssl_read()最终返回WANT_READ

然后当所有套接字都返回WANT_READ时,我等待ssl_read()。但是,我的应用仍在等待客户端已发送的数据。如果我让客户端启动另一个连接(同时保持原始文件处于活动状态),请选择return,这就是我所看到的:

  • 套接字1:select()返回数据,然后ssl_read()再次返回WANT_READ
  • 套接字2:ssl_read()返回WANT_READ
  • socket 3(new):ssl_read()返回数据,然后返回WANT_READ。

因此select检测到新连接并在我的循环中运行,循环遍历所有活动连接。这次,除了套接字3上的新数据之外,它还从上次发现套接字1中的数据。所以我的理论是select()第一次没有返回,因为我在套接字上等待接收的数据1已经到达并准备好等待我调用ssl_read()。但是上次我打电话给ssl_read时,我得到了WANT_READ。

1 个答案:

答案 0 :(得分:2)

SSL_read()返回负值时,您应该从SSL_get_error()获取错误代码。如果错误代码为 SSL_ERROR_WANT_READ ,则表示您应该等待(例如使用select()poll)该套接字可读(直到某些数据从网络到达)。如果发生这种情况,您应该再次在该套接字上重试SSL_read()您不必在您拥有的所有SSL套接字上重试SSL_read(),仅在那些返回 SSL_ERROR_WANT_READ 的SSL套接字上重试SSL_write()。您应该使用SSL_ERROR_WANT_WRITE(当它返回SSL_read()时)执行类似的事情。

但请注意,SSL_get_error()可能会返回SSL_ERROR_WANT_WRITE SSL_write()SSL_ERROR_WANT_READ可以返回n = SSL_read()。可能会发生这种情况,因为除了您的数据之外,SSL还需要发送/接收一些其他消息(例如,为了发送您的数据,它需要发送一些消息并首先接收响应)。

总结:

  1. n > 0返回时:

    a)n - &gt;您刚收到n < 0个字节的数据

    b)err = SSL_get_error() - &gt; select()已退回

    • SSL_ERROR_WANT_READ - &gt; SSL_read()直到套接字可读并再次致电select()
    • SSL_ERROR_WANT_WRITE - &gt; SSL_read()直到套接字可写并再次调用n = 0

    c)if(SSL_get_shutdown(SSL*) & SSL_RECEIVED_SHUTDOWN) - &gt; n = SSL_write():另一方干净关闭,否则shudown不干净,但SSL连接关闭你可以关闭套接字(SSL *对象也是)

  2. n > 0返回时:

    a)n - &gt;您刚刚发送了n < 0个字节的数据

    b)err = SSL_get_error() - &gt; select()已退回

    • SSL_ERROR_WANT_READ - &gt; SSL_write()直到套接字可读并再次致电select()
    • SSL_ERROR_WANT_WRITE - &gt; SSL_write直到套接字可写并再次调用n = 0

    c)if((err = SSL_get_error(SSL*,err)) == SSL_ERROR_ZERO_RETURN) - &gt; {{1}}:另一方干净关闭,否则shudown不干净,但SSL连接关闭你可以关闭套接字(SSL *对象也是)

  3. 我希望有所帮助。