为什么浏览器在选项卡关闭时发送突发请求?

时间:2021-03-26 07:02:29

标签: sockets http browser

这是来自我的自定义 Web 服务器的日志:

Master Writer update operation: WRT_RDINGS!
Master Writer waiting for updates on Web Queue...
Master Writer update operation: WRT_RDINGS!
Master Writer waiting for updates on Web Queue...
Master Writer update operation: WRT_RDINGS!
Master Writer waiting for updates on Web Queue...
Master Writer update operation: WRT_RDINGS!
Master Writer waiting for updates on Web Queue...
Master Writer update operation: WRT_RDINGS!
Master Writer waiting for updates on Web Queue...
Master Writer update operation: WRT_RDINGS!
Master Writer waiting for updates on Web Queue...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

Client Reader Thread 8 waiting for client input...
CTHD8: req orig: GET /upd HTTP/1.1
Host: 192.168.1.141
Connection: keep-ali

CTHD7: req orig: GET / HTTP/1.1
Host: 192.168.1.141
Connection: keep-alive

Client Reader Thread 7 waiting for client input...
CTHD7: req orig: GET / HTTP/1.1
Host: 192.168.1.141
Connection: keep-alive

Client Reader Thread 7 waiting for client input...
CTHD7: req orig: GET / HTTP/1.1
Host: 192.168.1.141
Connection: keep-alive

Client Reader Thread 7 waiting for client input...
CTHD7: req orig: GET / HTTP/1.1
Host: 192.168.1.141
Connection: keep-alive

Client Reader Thread 7 waiting for client input...
CTHD7: req orig: GET / HTTP/1.1
Host: 192.168.1.141
Connection: keep-alive

Master Writer update operation: WRT_UPDATE_HEAD!
Master Writer waiting for updates on Web Queue...
Master Writer update operation: WRT_DEFAULTS!

它使用 EventSource 向浏览器发送实时更新。所以 WRT_RDINGS 是正常操作。但是当我关闭站点选项卡时,它会不停地发送大量请求。之后我的服务器被 SIGPIPE 关闭(可能写入关闭的套接字)。在这种情况下,浏览器是 MS Edge。这是浏览器的正常行为吗?为什么会这样?是所有浏览器都这样还是仅基于 Chromium?

附言浏览器为 1 个标签打开 2 个套接字是正常的——一个用于基本 HTML 页面,另一个用于 EventSource?我想它可以打开任意多个,对吧?

1 个答案:

答案 0 :(得分:0)

我发现了这个问题...结果我被我自己糟糕的缓冲区位置和非常隐蔽的 read(2) 特殊功能误导了,这些功能在任何教程中都没有提到,只是在手册页中非常间接地提到。

我的读者线程的开始是这样的:

    while(1)
    {
        char buff[2048];
        res = read(sock, buff, 2048);
        if(res < 0)
        {
            delClient(s);
            pthread_exit(NULL);
        }

因此,我假设 buff 将在循环结束时被销毁并每次都重新创建。我知道这真的很愚蠢,因为它的局部变量并且它不像全局变量或静态变量那样自动用零初始化。我不知道我在想什么。但不管怎样,它实际上并不包含任何垃圾数据,但它保留了该线程中来自客户端的过去请求,例如:GET /upd HTTP/1.1

当我重做循环时:

while(1)
{
    char buff[2048];
    res = read(sock, buff, 2048);
    if(res < 0)
    {
        delClient(s);
        pthread_exit(NULL);
    }
    else if(res == 0)
    {
        printf("Client Reader Thread %d received empty request... Terminating!\n", sock);
        delClient(s);
        pthread_exit(NULL);
    }

我得到了这个结果,而不是请求垃圾邮件:

Client Reader Thread 7 received empty request... Terminating!
Client Reader Thread 8 received empty request... Terminating!
Client Reader Thread 9 received empty request... Terminating!
.......

终于开始看到真实的画面了... buff 正在重用它的最后一个请求,而 read(2) 实际上什么也没收到,0 字节。我确定是浏览器向我发送了垃圾邮件请求。

在文档中,它非常含糊且没有写清楚:

<块引用>

在支持查找的文件上,读取操作从 文件偏移量,文件偏移量按数字递增 读取的字节数。如果文件偏移量位于或超过文件末尾, 不读取任何字节,并且 read() 返回零。

也许它对套接字的工作方式与普通文件的工作方式不同......来自 C# Receive 方法的文档更清楚,也许这正是 read(2) 与套接字一起工作的方式:

<块引用>

如果远程主机用 Shutdown 关闭 Socket 连接 方法,并且已接收到所有可用数据,Receive 方法 将立即完成并返回零字节。

我也可以每次只将 memset-ed buff 设置为 0,但我想,检查一个 int == 0 花费的 CPU 比 memset-ing 2048 字节要少得多!

编辑:这个套接字也处于阻塞模式,所以我很惊讶地得知它可以突然停止阻塞并开始发送垃圾邮件零。

相关问题