1

我正在使用套接字在 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 似乎应对时间最长但最终也会断开连接。

4

1 回答 1

1

您应该调用SSL_accept()您的请求处理线程。这将允许您的侦听线程更快地处理 TCP 接受/侦听队列,并减少由于完整的接受/侦听队列而从 TCP 堆栈获得 RESET 的新连接的机会。

SSL 握手是计算密集型的。我猜你的垃圾邮件发送者可能没有使用 SSL 会话缓存,所以这会导致你的服务器使用最大数量的 CPU。这将导致它在服务其他连接或新的传入连接方面出现 CPU 不足。

于 2013-09-09T02:02:33.370 回答