WinHTTP over HTTP/2 多路复用

Posted

技术标签:

【中文标题】WinHTTP over HTTP/2 多路复用【英文标题】:WinHTTP over HTTP/2 with multiplexing 【发布时间】:2020-05-13 14:00:56 【问题描述】:

我想知道 Windows API WinHTTP 是否可以使用 HTTP/2 多路复用(一个 TCP 连接上的多个请求)。如果是这样,是否有示例代码如何归档?

我发现了来自 Microsoft (https://docs.microsoft.com/en-us/windows/win32/winhttp/about-winhttp) 的这条消息:

注意

WinHTTP 不可重入,除非在异步完成回调期间。也就是说,当线程有一个对 WinHttpSendRequest、WinHttpReceiveResponse、WinHttpQueryDataAvailable、WinHttpSendData 或 WinHttpWriteData 等 WinHTTP 函数的调用挂起时,它绝不能再次调用 WinHTTP,直到第一次调用完成。可能发生第二次调用的一种情况如下:如果应用程序将异步过程调用 (APC) 排队到调用 WinHTTP 的线程,并且如果 WinHTTP 在内部执行可警报等待,则 APC 可以运行。如果 APC 例程也调用 WinHTTP,它会重新进入 WinHTTP API,WinHTTP 的内部状态可能会被破坏。

这就是为什么我不确定是否可以异步调用 WinHttpReadData。

【问题讨论】:

【参考方案1】:

我最近发现了 WinHTTP 对 HTTP2 的支持,并且想知道是否可以进行完全多路复用,因为几乎没有关于它的文档。由于同步模式下的请求/响应不支持在不读取第一个请求的情况下发送第二个请求,因此我重新设计了我的应用程序以使用异步模式,并使用以下选项一次发出多个请求:

    const DWORD tlsProtocols = WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2 |
                   WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_3;

    const DWORD enableHTTP2Flag = WINHTTP_PROTOCOL_FLAG_HTTP2;

    const DWORD decompression = WINHTTP_DECOMPRESSION_FLAG_ALL;

    HINTERNET hSession = WinHttpOpen(L"WinHttp Test",
                      WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY,
                      WINHTTP_NO_PROXY_NAME,
                      WINHTTP_NO_PROXY_BYPASS,
                      WINHTTP_FLAG_ASYNC);

    WinHttpSetOption(hSession, WINHTTP_OPTION_SECURE_PROTOCOLS,
             (LPVOID)&tlsProtocols, sizeof(tlsProtocols));

    WinHttpSetOption(hSession, WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL,
             (LPVOID)&enableHTTP2Flag, sizeof(enableHTTP2Flag));

    WinHttpSetOption(hSession, WINHTTP_OPTION_DECOMPRESSION,
             (LPVOID)&decompression, sizeof(decompression));

    WinHttpSetStatusCallback(hSession, WinhttpStatusCallback,
                 WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS, 0);

    HINTERNET hConnect = WinHttpConnect(hSession,
                         L"example.com",
                         INTERNET_DEFAULT_HTTPS_PORT, 0);

尽管只调用了一次WinHttpConnect,但使用WinHttpOpenRequest 发出多个请求会导致WinHTTP 在内部打开到目标服务器的新连接,这表明很遗憾没有实现多路复用。

【讨论】:

以上是关于WinHTTP over HTTP/2 多路复用的主要内容,如果未能解决你的问题,请参考以下文章

我们应该在 HTTP/2 中复用多少并发请求

为啥使用多个连接进行 HTTP/2 多路复用演示?

你能用.Net Core HttpClient实现Http/2多路复用吗?

HTTP/2.0 多路复用如何与 TCP 一起工作?

HTTP/1.1 流水线和 HTTP/2 多路复用有啥区别?

除了多路复用和服务器推送之外,是啥让 http/2 比 http/1 更快?