如果将大文件加载到 C 网络服务器的内存缓冲区中会发生什么
What will happen if big file will be loaded in memory buffer in C webserver
我正在用 C 语言制作一个简单的 Web 服务器,用于为教育目的提供静态文件。我做了一个将文件发送到客户端的函数,它为整个文件分配了内存块。如果服务器硬件有 4 GB 的内存,并且客户端请求很大,例如,大小为 5 GB 的数据库文件,该怎么办?它不会使我的应用程序崩溃吗?
我的 serve_file 函数的主体(请注意省略了错误处理):
long fsize;
FILE *fp = fopen(filename, "rb");
fseek(fp, 0, SEEK_END);
fsize = ftell(fp);
rewind(fp);
char *buf = (char*) malloc(fsize);
fread(buf, fsize, 1, fp);
Server_TCP_Send(socket, buf, fsize);
fclose(fp);
free(buf);
最好的方法是使用循环读取和提供可管理块中的数据。这样文件有多大就无所谓了。您的方法可能会也可能不会导致系统崩溃。如果它没有崩溃,它可能会开始使用虚拟内存将数据分页到磁盘。这将导致大量抖动并降低您的系统速度,如果其他程序正在尝试 运行.
,这尤其糟糕
What if server hardware has 4 GB of memory, and client requested big, for example, database file that has 5 GB in size. Wouldn't it crash my application?
也许吧。也许不吧。 C 标准中没有任何内容直接说明这个问题。即使在实践中,您的 C 实现支持的已分配对象的大小也不一定限于物理内存的大小。现代机器具有虚拟内存系统,可以想象可以支持您描述的分配。如果确实分配成功,则没有特殊理由认为您的服务器会崩溃。
这里的主要风险是你没有检查分配是否成功。在可能失败的情况下,malloc()
调用将 return 一个空指针。将空指针作为 fread()
的第一个参数传递将产生未定义的行为。在这种情况下,这很可能表现为崩溃,但并非必须如此。如果您检查 malloc()
调用的 return 值,那么您可以优雅地失败而不是崩溃。
我注意到您也没有检查 fread()
的 return 值。如果失败,那么您最终可能会向客户端发送垃圾。作为一般规则,如果您确实关心是否发生任何错误,您应该检查函数调用的 return 值以查找错误指示器。
话虽如此,确实有更好的方法来完成您想要做的事情。除了失败的重大风险之外,在发送之前将整个文件读入内存可能会在实际开始向客户端传输之前引入明显的延迟。很可能足以自动或有机超时。从这个意义上讲,以较小的块读取很可能会快得多。还有其他选择,例如 将文件映射 到内存而不是实际读取它。
我正在用 C 语言制作一个简单的 Web 服务器,用于为教育目的提供静态文件。我做了一个将文件发送到客户端的函数,它为整个文件分配了内存块。如果服务器硬件有 4 GB 的内存,并且客户端请求很大,例如,大小为 5 GB 的数据库文件,该怎么办?它不会使我的应用程序崩溃吗?
我的 serve_file 函数的主体(请注意省略了错误处理):
long fsize;
FILE *fp = fopen(filename, "rb");
fseek(fp, 0, SEEK_END);
fsize = ftell(fp);
rewind(fp);
char *buf = (char*) malloc(fsize);
fread(buf, fsize, 1, fp);
Server_TCP_Send(socket, buf, fsize);
fclose(fp);
free(buf);
最好的方法是使用循环读取和提供可管理块中的数据。这样文件有多大就无所谓了。您的方法可能会也可能不会导致系统崩溃。如果它没有崩溃,它可能会开始使用虚拟内存将数据分页到磁盘。这将导致大量抖动并降低您的系统速度,如果其他程序正在尝试 运行.
,这尤其糟糕What if server hardware has 4 GB of memory, and client requested big, for example, database file that has 5 GB in size. Wouldn't it crash my application?
也许吧。也许不吧。 C 标准中没有任何内容直接说明这个问题。即使在实践中,您的 C 实现支持的已分配对象的大小也不一定限于物理内存的大小。现代机器具有虚拟内存系统,可以想象可以支持您描述的分配。如果确实分配成功,则没有特殊理由认为您的服务器会崩溃。
这里的主要风险是你没有检查分配是否成功。在可能失败的情况下,malloc()
调用将 return 一个空指针。将空指针作为 fread()
的第一个参数传递将产生未定义的行为。在这种情况下,这很可能表现为崩溃,但并非必须如此。如果您检查 malloc()
调用的 return 值,那么您可以优雅地失败而不是崩溃。
我注意到您也没有检查 fread()
的 return 值。如果失败,那么您最终可能会向客户端发送垃圾。作为一般规则,如果您确实关心是否发生任何错误,您应该检查函数调用的 return 值以查找错误指示器。
话虽如此,确实有更好的方法来完成您想要做的事情。除了失败的重大风险之外,在发送之前将整个文件读入内存可能会在实际开始向客户端传输之前引入明显的延迟。很可能足以自动或有机超时。从这个意义上讲,以较小的块读取很可能会快得多。还有其他选择,例如 将文件映射 到内存而不是实际读取它。