C - 睡眠(1) + fflush(stdout) 通过 curl 工作.不是通过网络浏览器



暂停(sleep(1)),当脚本通过curl命令
运行而不是在Web浏览器上运行时,工作正常。

但是通过网络浏览器..它将暂停所有暂停的总和(3 xsleep(1)),然后一次
打印它们

可以做些什么来确保网络浏览器的行为像 curl ?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
printf("Content-type: text/plainnn");
printf("%sn", "test 1");
fflush(stdout);
sleep(1);
printf("%sn", "test 2");
fflush(stdout);
sleep(1);
printf("%sn", "test 3");
fflush(stdout);
sleep(1);
printf("%sn", "test 4");
fflush(stdout);
return 0;
}

HTTP 最初设计用于交付文档。它有一个描述文档的标题,文档本身在正文中跟随,通常全部在一块中。

其中一个标头是Content-Length:,包含正文的大小,因此客户端知道需要多少数据。浏览器通常会尝试在开始显示之前获取整个文档。如您的示例,没有Content-Length:,浏览器只是等到连接关闭。

当然,设置Content-Length:在这里对您没有帮助,浏览器仍将等待整个文档。但也有一些分块传输编码,用于分几个部分交付文档。您可以自己实现它,例如:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char buffer[1024];
// note that "Content-Type" has an uppercase T, be exact when
// implementing a protocol!
printf("Content-Type: text/plainn");
printf("Transfer-Encoding: chunkednn");    
// snprintf() just for demonstration, you might need it for output
// of anything more complex than just fixed strings.
snprintf(buffer, 1024, "%s", "test 1");
// size of next chunk:
printf("%zxn", strlen(buffer));
printf("%sn", buffer);
fflush(stdout);
sleep(1); // or something more sensible, like, actual work...
// more data, finally indicate this was the last chunk:
printf("n");
return 0;
}

关于此解决方案可行性的一些说明:

  • 使用CGI,如图所示,"脚本"的运行持续时间通常有限制。可以在没有时间限制的情况下配置Web服务器,否则这只会遇到CGI超时。更好的解决方案是将其编写为自托管 Web 服务,请参阅 Basile 对某些链接的回答。

  • 这种方法的好处是它不需要客户端代码,因此它几乎可以与任何浏览器一起使用(分块传输支持非常常见)。缺点是您可能会由于某些环境条件而丢失TCP连接,恢复的唯一方法是手动重新加载页面。因此,如果可用,您可能希望使用javascript并使用WebSockets(最好,请参阅Basile的答案),或者,如果不可用,则执行长轮询。

HTTP比你想象的要复杂得多,CGI已经过时了(HTML5和AJAX应用程序)。考虑使用一些HTTP服务器库,如libonion(或制作一个FastCGI应用程序......)和/或一些HTTP客户端库,如libcurl

为了使您的东西在没有任何库的情况下工作(恕我直言这是一个错误),您需要研究更多的 HTTP 并在您的 HTTP 请求中添加更多标头,特别是Host:和响应:Content-Length:Connection: close

我强烈建议不要自己编写所有 HTTP 协议处理代码(因此请使用 HTTP 库)。

可以做些什么来确保网络浏览器的行为像 curl ?

什么都做不了;浏览器有权只处理完整的HTTP消息,这是有充分理由的。此外,大多数浏览器会(同时)打开到同一HTTP服务的多个连接

如果你需要一个现代浏览器的明显交互式行为(即一个随时间在视觉上演变的浏览器窗口),你应该考虑使用AJAX(使用HTML5)和WebSockets等技术,所以使用JavaScript(可能在服务器端生成)对浏览器进行编程。另请阅读有关单页应用程序的信息。查看 libonion 的 websocket 示例(它可能与您的需求非常相关)。顺便说一句,这种基于 WebSockets 和 AJAX 和 HTML5 的方法(相对于 Felix Palmen 提供的答案)具有优势,可以实现一些更视觉上花哨的东西(例如计算和显示行号),并且(使用一些额外的 Javascript 代码)添加清除显示的日志行的能力(仅在浏览器端)。

顺便说一下,特别是在 Linux 上 (使用像ext4这样的本地文件系统),您可能希望使用 inotify(7) 工具来接收文件更改的通知。您需要围绕 poll(2) (或较旧的 select(2) ...) 进行一些事件循环,但大多数 HTTP 相关库都提供了一个。

重要的是要了解HTTP不是一个交互式协议(每个请求都是浏览器发起的,并且只得到一个响应)。要添加交互性(流向服务器),您需要更多(例如WebSockets,它提供从服务器到浏览器的异步消息),或者至少一些"半繁忙轮询",即定期Javascript(在浏览器中)执行AJAX请求。

相关内容

最新更新