【发布时间】:2016-07-12 11:13:56
【问题描述】:
我有自己的使用 openssl 的网络服务器实现。
我正在使用 SSL_write 的阻塞版本来传输数据和 OSX 上最新的 Safari。
我的逻辑如下:
num_bytes = 0;
while( num_bytes < bytes_to_send) {
int n = SSL_write(...);
if (n <= 0) {
... // Handle error, break loop
}
num_bytes += n;
}
// Close the socket
我遇到的一个不常见的问题是 Safari 报告 Failed to load resource: The network connection was lost.
当我在 Safari 下的开发者面板中检查资源时,它显示接收到的字节数少于预期。
我已经调试了我的代码并确定SSL_write 报告在我关闭连接之前所有字节都已传输。
当我不关闭连接时,此错误不再发生。
这使我得出以下结论:
SSL_write 错误地报告了在实际发生之前已成功传输的字节数,并且在传输后立即关闭连接会缩短传输时间。
我是正确的,还是我缺少关于 SSL_write 的详细信息?
更新:
在检查了我处理 SSL_shutdown 的方式后,我看到报告了几个 SSL_ERROR_SYSCALL 错误。这可能与我的问题有关,也可能无关,因为这些错误不会在受影响的 http 传输后直接返回。奇怪的是,在受影响的 http 传输期间,除了阻塞调用的重试错误之外,SSL_shutdown 没有报告任何错误。
关机代码
// First shutdown SSL
SSL_CTX_free(ctx);
if (SSL_shutdown(ssl) == 0) {
// Call SSL Shutdown again
SSL_shutdown(ssl);
}
SSL_free(ssl);
// Now shutdown port
struct linger linger;
linger.l_onoff = 1;
linger.l_linger = 10;
setsockopt(socket, SOL_SOCKET, SO_LINGER, (char *)&linger,
sizeof(linger));
shutdown(socket, SHUT_WR);
while(recv(...) > 0) { }
closesocket(socket);
更新 #2
我设置了带有 ssl 解密的wireshark 来捕获错误。这是它的样子:
注意第一条绿线,它显示了来自 Safari 对 PatientSearch.js 的 HTTP 请求。现在第二条绿线显示了来自我的网络服务器的 HTTP 响应。此响应包含整个文件,然后是断开协议。
更新 #3
这件事变得越来越神秘。在检查了成功传输的 Wireshark 跟踪之后,成功传输与失败传输的协议模式没有区别。现在完全糊涂了。
【问题讨论】:
-
鉴于它在您保持连接打开时有效,我的猜测是该错误实际上在其他地方,即您在关闭套接字之前没有正确读取来自客户端的请求。见stackoverflow.com/a/33947985/3081018。
-
@SteffenUllrich 在阅读了您的评论后,我回去仔细检查了我的标头处理代码,并确认整个请求实际上是从套接字中检索的。我读出/打印了整个 HTTP 标头,使用 SSL_write 将数据返回给客户端,然后关闭了套接字。这样做之后,Safari 仍然会时断时续。
-
你能发布你的关机代码吗?对于 SSL 和底层套接字?
-
@hofan41:我知道移动设备上的 Safari 默认使用 HTTP pipelining,这导致我曾经实现的 HTTP 服务器出现问题。在发送响应后关闭套接字会导致仍在管道中的后续请求失败,Safari 对此并不满意。也许 Safari for OSX 也有类似的问题?
-
@hofan41:您的服务器使用的是 HTTP 1.0 还是 1.1?您的服务器是否在处理 HTTP keepalive 请求?在关闭套接字之前,您是否在响应中发送了
Connection: close标头?
标签: c++ sockets safari openssl