我正在研究一个小型Web服务器,它可以从浏览器接收GET请求并返回html文件。 serve_file
函数将响应消息发送到浏览器,而get_line
函数从套接字缓冲区获取一行。我不知道为什么必须读取并丢弃请求标头。我尝试在这两行中添加注释,然后浏览器显示一个连接重置页面。我猜服务器套接字的接收缓冲区已满,但是我不知道具体原因。有人可以解释吗?
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] = '\0';
//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);
}
答案 0 :(得分:0)
您观察到的行为是标准的套接字行为。
如果应用程序未读取从对等方接收的数据,并且应用程序在套接字上调用close
,则OS不会执行通常的TCP连接终结操作。它立即重置连接,而不是完成连接。如果应用程序确实确实希望在接收到的缓冲区中有未读数据时正常关闭连接,则它必须在调用shutdown(socket, SHUT_WR)
之前先调用close
。
为什么要以这种方式实现套接字API?因为这种处理可以避免dos攻击。如果close
执行正常的TCP会话终结,则可能会受到以下攻击:
close
。close
仅发送FIN
,然后等待对等方关闭。服务器资源保持分配状态,因为常规FIN
仅关闭了指向客户端的方向。客户端仍然可以发送数据,并且recv缓冲区不会被释放。但是,当关闭启动连接重置时,与此TCP连接相关的资源将立即释放。这样一来,dos攻击就会变得更加复杂。
有关更多详细信息,请参见https://www.spinics.net/lists/linux-c-programming/msg01345.html。