我有一个阻塞的SSL BIO对象,我想要发送数据。 问题是连接在远程端被closures了,直到我读完(BIO_write不会返回错误),我才find这个连接。 但是,因为我不想阻止,所以在发送之前我无法阅读。 最后,负责发送数据的代码和负责读取的代码是分开的,意味着失败的读取不能触发另一个发送。 我该如何解决?
有两种“关闭”状态,被称为“半关闭”状态。 他们主要是关心套接字的一端还是另一端将要发送更多的应用程序数据。 当您的recv
呼叫返回0时,实际上是通知您没有更多的数据将被接收。 但是,发送数据还是可以的,除非send
调用发出其他类型的错误信号,比如EPIPE
或者ECONNRESET
(我不确定这些winsock的等效窗口是什么,但是我知道它们在那里)。 如果SSL_write
没有返回错误,那是因为套接字的另一端仍然接受数据。
recv
调用允许对“无数据”状态进行非阻塞检查,并且可以这样做:
char c; int r = recv(sock, &c, 1, MSG_DONTWAIT|MSG_PEEK);
如果r
为0
,则套接字已经接收到从另一端没有更多待处理数据的指示。 否则,对于一个数据字节(由于MSG_PEEK
,它仍然在输入缓冲区中)或-1
,调用将返回1
。 如果errno
是EAGAIN
(这可能是因为MSG_DONTWAIT
)没有错误。 应该查询任何其他的errno
值,但可能表示套接字处于无效状态,需要关闭。
在套接字被关闭之前,OpenSSL应用程序应该确保SSL_shutdown
已经返回1.然后,在SSL
对象被销毁之后(使用SSL_free
),套接字close
发生。 这意味着除非应用程序发生异常,否则使用OpenSSL的套接字的双方都应该看到SSL_shutdown
返回1
,然后双方都可以安全地关闭连接。
如果要检查SSL
上下文的关闭状态,可以使用SSL_get_shutdown
,它将报告另一端是否已启动SSL_shutdown
序列。