我正在尝试使用 OpenSSL 库用 C++ 编写 HTTPS Web 服务器。
我从 OpenSSL 网站上的简单 TLS 服务器示例开始,但我无法弄清楚如何读取超过 16'384 字节的数据。
所有代码与简单 TLS 服务器示例中的相同,这是我读取数据的部分:
if (SSL_accept(ssl) <= 0) {
ERR_print_errors_fp(stderr);
} else {
while (true) {
char buffer[16'384];
const auto bytes = SSL_read(ssl, buffer, 16'384);
const auto ssl_error = SSL_get_error(ssl, bytes);
const auto pending = SSL_pending(ssl);
std::cout << bytes << std::endl; // This is always 16'384 when the requests exceeds 16 kB
std::cout << ssl_error << std::endl; // This is always 0 (SSL_ERROR_NONE)
std::cout << pending << std::endl; // This is always 0 since we read a full record of data and there's no more pending data in the record
// How to know if there is more data to read?
if (ssl_error == SSL_ERROR_NONE && pending == 0) {
// This condition will always be true (see previous comments)
break;
}
}
const auto response = "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World!";
SSL_write(ssl, response, strlen(response));
}
我正在使用 Postman 或 Firefox 发出请求来测试这一点,在这两种情况下,退出循环的条件都是 true,即使请求是否超过 16kB。
读取完整记录后,我想知道是否还有另一条记录可以使用循环读取请求的其余部分。
正如我的代码中的注释所暗示的,我做了一些研究:
我也尝试过使套接字异步,但 SSL_read 似乎保持同步。
我遇到过这个例子,这似乎是 BIO 的一个非常简单的用法,但我也没有设法让它工作。
当然,我也看过这篇文章,它让我明白了为什么我无法阅读超过 16 kB,但没有真正解决问题。
使用 BIO 是正确的方法吗?如果是这样,怎么办?我不太懂BIO。 或者有没有不使用BIO的解决方案?
SSL_pending
仅表示 SSL 对象内部是否有更多数据缓冲。它没有提及操作系统套接字缓冲区中缓冲的数据、仍在传输中的数据或发送方尚未传输的数据。
因此,不要依赖 SSL_pending
作为退出循环的条件。相反,请再次拨打
SSL_read
。仅当返回等于或小于 0 时,SSL 会话内就没有更多内容可供读取。