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