2

这里

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

它指出

“...这就是为什么理解任何端口上任何可能的转发进度(以及返回 WANT_READ 的写入操作可能已经取得转发进度!)要求您重试所有端口上的所有挂起操作非常重要的原因...... "

那么我是否正确理解SSL_read()返回的WANT_READ可能已经取得了进展(即使它没有返回任何数据)?

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

返回时select(),循环通过 3 个套接字调用ssl_read()它们中的每一个。

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

由于循环已通过 3 个套接字,它在那里等待并挂起。这种情况会发生吗?

如果是这种情况,我如何查看是否在所有 3 个插槽上都无法取得更多进展?例如,假设循环贯穿;

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

但是根据上面的引用(任何向前的进展都需要重试所有挂起的操作),我应该再次重试所有套接字;所以第二次通过循环;

  • socket 1 现在返回数据,然后WANT_READ
  • 套接字 2 返回WANT_READ
  • 套接字 3 现在返回数据(因为套接字 1 上的读取取得了足够的进展,使套接字 3 返回数据),然后WANT_READ.

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

编辑1:

所以我看到的是这样的:

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

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

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

  • socket 1:ssl_read()返回数据,然后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。

4

1 回答 1

3

返回负值时SSL_read(),应从SSL_get_error(). 如果错误代码是SSL_ERROR_WANT_READ这意味着您应该等待(例如使用select()or poll)该套接字可读(直到一些数据从网络到达)。发生这种情况时,您应该再次在该套接字上重试 SSL_read() 。您不必重试SSL_read()您拥有的所有 SSL 套接字,只需在那些返回SSL_ERROR_WANT_READ的套接字上重试。SSL_write()你应该用(当它返回时)做类似的事情SSL_ERROR_WANT_WRITE

但是要小心,SSL_read()可能会返回(SSL_get_error()即)SSL_ERROR_WANT_WRITE并且SSL_write()可以返回SSL_ERROR_WANT_READ。它可能会发生,因为 SSL 需要发送/接收除了您的数据之外的一些附加消息(例如,为了发送您的数据,它需要先发送一些消息并接收响应)。

总结一下:

  1. 返回时n = SSL_read()

    a) n > 0--> 你刚刚收到n数据字节

    b) n < 0-->err = SSL_get_error()返回

    • SSL_ERROR_WANT_READ -->select()直到套接字可读并SSL_read()再次调用
    • SSL_ERROR_WANT_WRITE -->select()直到套接字可写并SSL_read()再次调用

    c) n = 0--> if(SSL_get_shutdown(SSL*) & SSL_RECEIVED_SHUTDOWN): 对方做了干净的关机,否则关机不干净,但是 SSL 连接关闭了你可以关闭套接字(SSL* 对象也是)

  2. 返回时n = SSL_write()

    a) n > 0--> 你刚刚发送n了数据字节

    b) n < 0-->err = SSL_get_error()返回

    • SSL_ERROR_WANT_READ -->select()直到套接字可读并SSL_write()再次调用
    • SSL_ERROR_WANT_WRITE -->select()直到套接字可写并SSL_write再次调用

    c) n = 0--> if((err = SSL_get_error(SSL*,err)) == SSL_ERROR_ZERO_RETURN): 对方做了干净的关机,否则关机不干净,但是 SSL 连接关闭了你可以关闭套接字(SSL* 对象也是)

我希望这会有所帮助。

于 2013-01-18T05:40:19.220 回答