为什么网络服务器在发送响应之前应该清除套接字接收缓冲区?
Why web server should clear away socket receive buffer before sending response?
我正在研究一个微型网络服务器,它可以从浏览器接收 GET-request 和 return 一个 html 文件。 serve_file
-函数向浏览器发送响应消息,get_line
-函数从套接字缓冲区获取一行。我不知道为什么必须 读取并丢弃请求 headers。我尝试评论这两行,浏览器显示连接重置页面。估计是server socket receive buffer满了,具体原因不知道。谁能解释一下?
source code
/* Send a regular file to the client. Use headers, and report */
void serve_file(int client, const char *filename) {
FILE *resource = NULL;
int numchars = 1;
char buf[1024];
buf[0] = 'A'; buf[1] = '[=10=]';
//why?
while ((numchars > 0) && strcmp("\n", buf)) /* read & discard request headers */
numchars = get_line(client, buf, sizeof(buf));
resource = fopen(filename, "r");
if (resource == NULL)
not_found(client);
else {
headers(client, filename); //send headers to tcp buffer
cat(client, resource); //send index.html to tcp buffer
}
fclose(resource);
}
您观察到的行为是标准套接字行为。
如果应用程序未读取从对等点接收的数据并且应用程序在套接字上调用 close
,则 OS 不会执行通常的 TCP 连接终止。它立即重置连接而不是完成。如果应用程序真的想在接收缓冲区中有未读数据时优雅地关闭连接,那么它必须在调用 close
.
之前调用 shutdown(socket, SHUT_WR)
为什么套接字 API 是这样实现的?因为这样处理可以避免dos攻击。如果 close
执行正常的 TCP 会话终止,则可能发生以下攻击:
- 恶意客户端打开 TCP 连接
- 服务器接受连接并开始接收数据
- 客户端发送连续的随机数据流
- 服务器快速检测到接收到的数据有误,并在套接字上调用
close
。
close
只是发送一个 FIN
然后等待对等点关闭。服务器资源保持分配,因为正常 FIN
只是关闭朝向客户端的方向。客户端仍然可以发送数据并且接收缓冲区不会被释放。
但是当关闭启动连接重置时,与此 TCP 连接相关的资源将立即释放。那么dos攻击就复杂一点了。
有关详细信息,请参阅 https://www.spinics.net/lists/linux-c-programming/msg01345.html。
我正在研究一个微型网络服务器,它可以从浏览器接收 GET-request 和 return 一个 html 文件。 serve_file
-函数向浏览器发送响应消息,get_line
-函数从套接字缓冲区获取一行。我不知道为什么必须 读取并丢弃请求 headers。我尝试评论这两行,浏览器显示连接重置页面。估计是server socket receive buffer满了,具体原因不知道。谁能解释一下?
source code
/* Send a regular file to the client. Use headers, and report */
void serve_file(int client, const char *filename) {
FILE *resource = NULL;
int numchars = 1;
char buf[1024];
buf[0] = 'A'; buf[1] = '[=10=]';
//why?
while ((numchars > 0) && strcmp("\n", buf)) /* read & discard request headers */
numchars = get_line(client, buf, sizeof(buf));
resource = fopen(filename, "r");
if (resource == NULL)
not_found(client);
else {
headers(client, filename); //send headers to tcp buffer
cat(client, resource); //send index.html to tcp buffer
}
fclose(resource);
}
您观察到的行为是标准套接字行为。
如果应用程序未读取从对等点接收的数据并且应用程序在套接字上调用 close
,则 OS 不会执行通常的 TCP 连接终止。它立即重置连接而不是完成。如果应用程序真的想在接收缓冲区中有未读数据时优雅地关闭连接,那么它必须在调用 close
.
shutdown(socket, SHUT_WR)
为什么套接字 API 是这样实现的?因为这样处理可以避免dos攻击。如果 close
执行正常的 TCP 会话终止,则可能发生以下攻击:
- 恶意客户端打开 TCP 连接
- 服务器接受连接并开始接收数据
- 客户端发送连续的随机数据流
- 服务器快速检测到接收到的数据有误,并在套接字上调用
close
。 close
只是发送一个FIN
然后等待对等点关闭。服务器资源保持分配,因为正常FIN
只是关闭朝向客户端的方向。客户端仍然可以发送数据并且接收缓冲区不会被释放。
但是当关闭启动连接重置时,与此 TCP 连接相关的资源将立即释放。那么dos攻击就复杂一点了。
有关详细信息,请参阅 https://www.spinics.net/lists/linux-c-programming/msg01345.html。