问题描述
这里
http://marc.info/?l=openssl-users&m=124386218929227
它指出
"...这就是为什么理解任何端口上任何可能的转发进度(以及返回 WANT_READ 的写操作可能已经取得转发进度!)要求您重试所有端口上的所有挂起操作非常重要的原因.……"
"...This is why it is very important to understand that any possible forward progress on any port (and a write operation that returns WANT_READ may have made forward progress!) requires you to retry all pending operations on all ports...."
那么我是否正确理解返回 WANT_READ
的 SSL_read()
可能已经取得了进展(即使它没有返回任何数据)?
So am I correct in understanding that an SSL_read()
that returned WANT_READ
may have made forward progress (even if it did not return any data)?
我有一个事件驱动的单线程应用程序,它有 3 个非阻塞 ssl 套接字.当每个套接字完成其连接时,我会读取套接字,直到获得 WANT_READ
.我的理解是 WANT_READ
意味着我现在可以调用 select()
并等待套接字准备好再次读取.
I have an event driven single threaded app that has 3 non blocking ssl sockets. When each socket completes its connection, I have the sockets read until I get a WANT_READ
. My understanding is that a WANT_READ
means I may now invoke select()
and wait until the socket is ready for reading again.
当 select()
返回时,循环遍历 3 个套接字,在每个套接字上调用 ssl_read()
.
When select()
returns, a loop goes through the 3 sockets calling ssl_read()
on each of them.
假设对套接字 1 的读取返回 WANT_READ
并且没有数据.套接字 2 是否有可能返回一些数据,当没有更多可读取的内容时返回 WANT_READ
,并且现在取得了一些进展,因此对套接字 1 的读取现在可以返回数据?但由于循环已经完成了对套接字 1 的读取,因此不会发生.
Say a read on Socket 1 returned WANT_READ
and no data.Is it possible that Socket 2 returns some data, returns WANT_READ
when there is nothing more to read, and has now made some progress so a read on socket 1 may now return data? But as the loop has already done the read for socket 1, it will not happen.
当循环通过 3 个套接字时,它在那里等待并挂起.这种情况会发生吗?
As the loop has run through the 3 sockets, it waits there and hangs. Could this situation happen?
如果是这种情况,我如何查看是否在所有 3 个套接字上都无法取得更多进展?例如,假设循环运行;
If this is the case, how do I see if no more progress can be made on all 3 sockets?For example, say the loop runs through;
- 套接字 1 返回
WANT_READ
. - socket 2 返回一些数据,然后
WANT_READ
(并取得进展使得 socket 1 现在可以返回数据) - socket 3 返回
WANT_READ
.
- socket 1 returns
WANT_READ
. - socket 2 returns some data, then
WANT_READ
(and makes progress such that socket 1 can now return data) - socket 3 returns
WANT_READ
.
但是根据上面的引用(任何前进的过程都需要重试所有挂起的操作),我应该再次重试所有套接字;所以第二次运行循环;
But based on the quote above (where any forward progress requires retrying all pending operations), I should retry all sockets again; so the second run through the loop;
- socket 1 现在返回数据,然后
WANT_READ
- socket 2 返回
WANT_READ
- 套接字 3 现在返回数据(因为套接字 1 上的读取取得了足够的进展,套接字 3 返回数据),然后是
WANT_READ
.
但是如果套接字 3 上的最后一次读取取得了进展,那么套接字 2 现在再次返回数据呢?所以我的问题是(如果我的理解是正确的),我如何判断是否不能取得更多进展?
But what if the last read on socket 3 made progress so socket 2 now returns data again? So my question is (if my understanding is correct), how can I tell if no more progress can be made?
编辑 1:
所以我看到的是这个:
我的循环遍历连接到 client1 的所有套接字(例如说有 2 个套接字)
My loop runs through all sockets (eg say there are 2 sockets) connected to client1
- socket 1:
ssl_read()
返回 WANT_READ - socket 2:
ssl_read()
返回数据,ssl_read()
再次返回数据,然后ssl_read()
最后返回WANT_READ
- socket 1:
ssl_read()
returns WANT_READ - socket 2:
ssl_read()
returns data,ssl_read()
returns data again, thenssl_read()
finally returns WANT_READ
然后当所有套接字都返回 WANT_READ 时,我等待 select()
.但是,我的应用程序仍在等待客户端已经发送的数据.如果我让客户端开始另一个连接(同时保持原始连接处于活动状态),选择返回,这就是我看到的:
Then as all sockets have returned WANT_READ, I wait on select()
. However my app is still waiting for data that the client has already sent. If I get the client to start another connection (while keeping the originals active), select returns and this is what I see:
- socket 1:
ssl_read()
返回数据,然后ssl_read()
再次返回 WANT_READ - 套接字 2:
ssl_read()
返回 WANT_READ - socket 3(new):
ssl_read()
返回数据,然后返回 WANT_READ.
- socket 1:
ssl_read()
returns data, thenssl_read()
again returns WANT_READ - socket 2:
ssl_read()
returns WANT_READ - socket 3(new):
ssl_read()
returns data, then returns WANT_READ.
So select 检测到新连接并运行我的循环,它遍历所有活动连接.这一次,除了socket 3上的新数据之外,它已经找到了上次socket 1的数据. 所以我的理论是select()第一次没有返回,因为我在socket上等待接收的数据1 已经到了,准备好了,等着我调用 ssl_read().但是上次我调用 ssl_read 时,我得到了 WANT_READ.
So select detects the new connection and runs through my loop, which goes through all active connections. This time, it has found data from socket 1 from last time, in addition to the new data on socket 3. So my theory is that select() doesn't return the first time because the data I'm waiting to receive on socket 1 has already arrived and is ready and waiting for me to call ssl_read(). But last time I called ssl_read, I got WANT_READ.
推荐答案
当SSL_read()
返回负值时,你应该从SSL_get_error()
获取错误代码.如果错误代码是 SSL_ERROR_WANT_READ,则意味着您应该等待(例如使用 select()
或 poll
)该套接字可读(直到一些数据来自网络).当它发生时,您应该再次在该套接字上重试 SSL_read() .您不必在您拥有的所有 SSL 套接字上重试 SSL_read()
,只需在返回 SSL_ERROR_WANT_READ 的那些套接字上重试即可.你应该用 SSL_write()
做类似的事情(当它返回 SSL_ERROR_WANT_WRITE
时).
When SSL_read()
returns a negative value, you should obtain the error code from SSL_get_error()
. If the error code is SSL_ERROR_WANT_READ it means that you should wait (e.g. using select()
or poll
) for that socket to be readable (untill some data arrives from the network). When it happens you should retry SSL_read() on that socket again. You don't have to retry SSL_read()
on all SSL sockets that you have, only on those ones that returned SSL_ERROR_WANT_READ. You should do simmilar things with SSL_write()
(when it returns SSL_ERROR_WANT_WRITE
).
请注意,SSL_read()
可能会返回(SSL_get_error()
即)SSL_ERROR_WANT_WRITE
和 SSL_write()
可以返回 SSL_ERROR_WANT_READ
.这可能会发生,因为 SSL 需要发送/接收除您的数据之外的一些其他消息(例如,为了发送您的数据,它需要先发送一些消息并接收响应).
Be careful though, SSL_read()
can potentially return (SSL_get_error()
that is) SSL_ERROR_WANT_WRITE
and SSL_write()
can return SSL_ERROR_WANT_READ
. It may happen, because SSL needs to send/receive some additional messages besides your data (e.g. in order to send your data it needs to send some message and receive response first).
总结:
当
n = SSL_read()
返回时:
a)n >0
--> 你刚刚收到了 n
个字节的数据
a)n > 0
--> you have just received n
bytes of data
b)n -->
err = SSL_get_error()
返回
- SSL_ERROR_WANT_READ -->
select()
直到套接字可读并再次调用SSL_read()
- SSL_ERROR_WANT_WRITE -->
select()
直到套接字可写并再次调用SSL_read()
- SSL_ERROR_WANT_READ -->
select()
untill socket is readable and callSSL_read()
again - SSL_ERROR_WANT_WRITE -->
select()
untill socket is writable and callSSL_read()
again
c)n = 0
--> if(SSL_get_shutdown(SSL*) & SSL_RECEIVED_SHUTDOWN)
:对方做了干净关机,否则关机不干净,但 SSL 连接已关闭,您可以关闭套接字(也有 SSL* 对象)
c)n = 0
--> if(SSL_get_shutdown(SSL*) & SSL_RECEIVED_SHUTDOWN)
: the other side did clean shutdown, otherwise the shudown was not clean, but the SSL connection is closed you can close the socket (SSL* object too)
当 n = SSL_write()
返回时:
a)n >0
--> 你刚刚发送了 n
个字节的数据
a)n > 0
--> you have just sent n
bytes of data
b)n -->
err = SSL_get_error()
返回
- SSL_ERROR_WANT_READ -->
select()
直到套接字可读并再次调用SSL_write()
- SSL_ERROR_WANT_WRITE -->
select()
直到套接字可写并再次调用SSL_write
- SSL_ERROR_WANT_READ -->
select()
untill socket is readable and callSSL_write()
again - SSL_ERROR_WANT_WRITE -->
select()
untill socket is writable and callSSL_write
again
c)n = 0
--> if((err = SSL_get_error(SSL*,err)) == SSL_ERROR_ZERO_RETURN)
: 对方确实关闭了,否则关闭不干净,但 SSL 连接已关闭,您可以关闭套接字(也有 SSL* 对象)
c)n = 0
--> if((err = SSL_get_error(SSL*,err)) == SSL_ERROR_ZERO_RETURN)
: the other side did clean shutdown, otherwise the shudown was not clean, but the SSL connection is closed you can close the socket (SSL* object too)
希望能帮到你.
这篇关于如何判断何时无法在 SSL 连接上取得更多进展的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!