使用 WinAPI 的 InternetReadFile() 进行长轮询

Posted

技术标签:

【中文标题】使用 WinAPI 的 InternetReadFile() 进行长轮询【英文标题】:Longpolling with WinAPI's InternetReadFile() 【发布时间】:2019-05-23 17:03:00 【问题描述】:

我正在编写一个跨平台应用程序。我需要从 longpoll url 获取数据。

在 Mac/Linux 上我可以使用 curl,curl_easy_perform() 会自动处理所有事情。

在 Windows 上,我必须使用本机 api。下面的代码适用于普通 url,但是当我尝试使用 longpoll url 时,它会立即退出 (nr_read == 0) 而不是等到有新数据:

...
   flags =
 INTERNET_FLAG_HYPERLINK | INTERNET_FLAG_IGNORE_CERT_CN_INVALID |
 INTERNET_FLAG_IGNORE_CERT_DATE_INVALID |
 INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP |
 INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS | INTERNET_FLAG_NO_AUTH |
 INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_UI |
 INTERNET_FLAG_NO_COOKIES  |  
 INTERNET_FLAG_KEEP_CONNECTION |
 INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD 
 INTERNET_FLAG_SECURE;
...

HINTERNET internet = InternetOpenA(user_agent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
HINTERNET connect = InternetConnectA(internet, host, port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
HINTERNET request = HttpOpenRequest(connect, req_typ, path, "HTTP/1.1", NULL, NULL, flags, NULL);


#define BUF_MAX 1024
TCHAR buf[BUF_MAX + 1];
int nr_read = 0;
while (1) 
     int ok = InternetReadFile(request, buf, BUF_MAX, &nr_read);
     if (!ok) 
             puts("not ok");
             break;
     
     if (nr_read == 0) 
             puts("nr read 0, breaking");
             break;
     
     buf[nr_read] = 0;
     printf("buf='%s'\n", buf);
     nr_read = 0;

我得到的响应标头:

HTTP/1.1 101
Switching Protocols
upgrade: websocket
connection: upgrade

握手之后,libcurl 继续传输 websocket 数据(我可以手动处理),但 InternetReadFile() 只是退出。

我用

发送一个 http 请求
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: key
Sec-WebSocket-Version: 13

服务器回答上面的标题,然后 libcurl 给我"type": "hello" 等等,但InternetReadFile() 只是退出。

【问题讨论】:

在调用 InternetReadFile 或任何 Windows Socket/Wininet 函数之前。你能确认你正在调用 WSAStartup 吗?并且 InternetOpenUrl/HttpOpenRequest 成功了。 我没有 WSAStartup(),添加它没有帮助。处理 InternetConnectA() 和 HttpOpenRequest() 错误。 我感觉必须有一个互联网标志才能启用长轮询...... @Nina 使用WinInet时不需要调用WSAStartup(),直接使用Winsock时才需要调用 谢谢@RemyLebeau。我现在明白尝试使用 HTTP 库处理 websocket 是多么荒谬(尽管 libcurl 以某种方式神奇地处理了它)。您可以创建一个简短的答案以便我接受吗? 【参考方案1】:

我最终使用了 libcurl :)

..

【讨论】:

以上是关于使用 WinAPI 的 InternetReadFile() 进行长轮询的主要内容,如果未能解决你的问题,请参考以下文章

自定义控件,winapi

winApi使用c++创建进程

Ownerdrawn托盘图标(winapi)?

如何使用winapi实现类似Steam的窗口?

如何更改静态文本控件(winapi)的字体?

无法使用 WinAPI 显示窗口