我正在使用套接字在 C 中编写一个 HTTP 服务器。它可以侦听多个端口并在每个端口 1 个线程的基础上运行侦听循环,每个循环产生另一个线程来传递响应
该代码在交付标准 HTTP 响应时运行良好。我将其设置为响应带有 JavaScript 代码的 HTML 页面,该代码只是反复刷新浏览器以对服务器进行压力测试。我已经在我的计算机作为服务器运行时对此进行了测试,另外 4 台其他设备同时向它发送请求。
没有崩溃,没有掉线,也没有内存泄漏。CPU 使用率永远不会超过 5%,在 2.0 GHz Intel Core 2 Duo 上以 HTTP 模式运行,4 个设备发送垃圾邮件请求。
我昨天刚刚添加了 OpenSSL,因此它可以通过 HTTPS 提供安全响应。这进行得相当顺利,因为我似乎只需要用它们的 OSSL 对应项替换一些标准套接字调用以实现安全模式(基于这个问题的解决方案:将简单的套接字转换为 SSL 套接字)。
每个连接有一个 SSL 上下文和SSL
结构。它确实有效,但不是很可靠。同样,每个响应都发生在自己的线程上,但是安全模式下的多个/快速/并发请求似乎是随机丢弃的,尽管我的代码中仍然没有崩溃或内存泄漏。
当连接断开时,浏览器要么说它正在等待一个永远不会发生的响应(Chrome),要么只是说连接已重置(Firefox)。
作为参考,这里是更新的连接创建和关闭代码。
连接创建代码(监听循环的主要部分):
// Note: sslCtx and sslConnection exist
// elsewhere in memory allocated specifically
// for each connection.
struct sockaddr_in clientAddr; // memset-ed to 0 before accept
int clientAddrLength = sizeof(clientAddr);
...
int clientSocketHandle = accept(serverSocketHandle, (struct sockaddr *)&clientAddr, &clientAddrLength);
...
if (useSSL)
{
int use_cert, use_privateKey, accept_result;
sslCtx = SSL_CTX_new(SSLv23_server_method());
SSL_CTX_set_options(sslCtx, SSL_OP_SINGLE_DH_USE);
use_cert = SSL_CTX_use_certificate_file(sslCtx, sslCertificatePath , SSL_FILETYPE_PEM);
use_privateKey = SSL_CTX_use_PrivateKey_file(sslCtx, sslCertificatePath , SSL_FILETYPE_PEM);
sslConnection = SSL_new(sslCtx);
SSL_set_fd(sslConnection, clientSocketHandle);
accept_result = SSL_accept(sslConnection);
}
... // Do other things and spawn request handling thread
连接关闭代码:
int recvResult = 0;
if (!useSSL)
{
shutdown(clientSocketHandle, SHUT_WR);
while (TRUE)
{
recvResult = recv(clientSocketHandle, NULL, 0, 0);
if (recvResult <= 0) break;
}
}
else
{
SSL_shutdown(sslConnection);
while (TRUE)
{
recvResult = SSL_read(sslConnection, NULL, 0);
if (recvResult <= 0) break;
}
SSL_free(sslConnection);
SSL_CTX_free(sslCtx);
}
closesocket(clientSocketHandle);
同样,这对于 HTTP 响应来说是 100% 完美的。HTTPS 响应可能出了什么问题?
更新
我已经使用多线程环境的 OpenSSL 回调更新了代码,并且使用此问题的答案中的代码,服务器稍微更可靠:OpenSSL 和多线程。
我编写了一个小型命令行程序,通过 HTTPS 请求向服务器发送垃圾邮件,并且它不会丢弃任何同时运行的 5 个多个实例的连接。多个 Firefox 实例似乎也没有断开任何连接。
然而,有趣的是,现代基于 WebKit 的浏览器仍然会断开连接。Chrome 在垃圾邮件发送不到 30 秒时开始断开连接,iPhone 4 (iOS 5.1) 上的 Safari 在说连接丢失之前很少刷新 3 次,但 iPad 2 (iOS 5.0) 上的 Safari 似乎应对时间最长但最终也会断开连接。