【发布时间】:2012-06-13 12:05:36
【问题描述】:
我有一个要向其发送数据的阻塞 SSL BIO 对象。问题是远程端的连接已关闭,在我进行读取之前我无法找到它(BIO_write 不会返回错误)。但是,我在发送之前无法阅读,因为我不想阻止。最后,负责发送数据的代码和负责读取的代码是分开的,这意味着读取失败不能触发另一个发送。我该如何解决这个问题?
【问题讨论】:
我有一个要向其发送数据的阻塞 SSL BIO 对象。问题是远程端的连接已关闭,在我进行读取之前我无法找到它(BIO_write 不会返回错误)。但是,我在发送之前无法阅读,因为我不想阻止。最后,负责发送数据的代码和负责读取的代码是分开的,这意味着读取失败不能触发另一个发送。我该如何解决这个问题?
【问题讨论】:
有两种“关闭”状态,称为“半关闭”状态。它们主要与套接字的一侧或另一侧是否将发送更多应用程序数据有关。当您的recv 调用返回 0 时,它实际上是在通知您没有更多数据要接收。但是,仍然可以发送数据,除非send 调用发出某种其他类型的错误,例如EPIPE 或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 在 SSL 对象被销毁(使用 SSL_free)之后发生。这意味着,除非应用程序执行异常操作,否则使用 OpenSSL 的套接字的双方都应该看到SSL_shutdown 返回1,然后双方都可以安全地关闭连接。
如果要检查SSL上下文的关闭状态,可以使用SSL_get_shutdown,它会报告另一端是否启动了SSL_shutdown序列。
【讨论】: