【问题标题】:HTTP/1.0 server in C, how to send big files to the client?C中的HTTP / 1.0服务器,如何向客户端发送大文件?
【发布时间】:2016-07-05 22:45:30
【问题描述】:

我必须(作为作业)用 C 语言编写一个小型 HTTP/1.0 服务器。

这是我的问题:我不知道如何处理客户端请求的页面尺寸非常大的情况。

我认为最好先读取整个文件,然后开始向客户端发送回复(包括状态行和标题),主要原因是我可以适当地设置状态码。例如,假设服务器已经读取并存储为客户端想要的文件的一半字符串,read() 失败。然后我会继续设置“HTTP/1.0 500 Internal server error”作为状态行。

这种方法的问题是,如果文件很大,它会占用太多内存(并且由于每个连接都由单独的线程处理,如果多个线程将相当大的文件存储为字符串,那么内存使用量会增加更糟)。

作为一种解决方案,我考虑打开文件,发送状态行和标题,然后将给定数量(不太大)的字节读入缓冲区并迭代发送缓冲区中的内容,直到我读完/发送整个文件。

这解决了问题,但同样,如果read() 在文件进行到一半时失败了怎么办?由于内部错误,客户端请求无法完成,因此 500 状态码是合适的,但我已经通过套接字发送了 200 OK 消息!

这个问题通常在 HTTP 服务器中是如何处理的?

【问题讨论】:

  • 在同一个文件上成功调用read() 后,您希望read() 遇到哪个错误?我在实践中看到的唯一一个是EINTR,它是无害的。此外,根据您的平台,您可能有更好的选择,例如sendfile()

标签: c file http server


【解决方案1】:

作为一种解决方案,我考虑打开文件,发送状态行和标题,然后将给定数量(不太大)的字节读入缓冲区并迭代发送缓冲区中的内容,直到我读完/发送整个文件。

这正是你应该做的。事先查询文件大小,以便将其放入Content-Length 响应标头中,然后在发送了这么多字节后停止读取+发送循环。

如果您可以切换到 HTTP 1.1,那么您还有另一个选择。您可以省略Content-Length 标头,而是发送Transfer-Encoding: chunked 标头,然后您可以以chunked 格式发送每个缓冲区(请参阅RFC 2616 Section 3.6.1),其中每个块指定自己的字节大小。通过发送一个长度为 0 的块来终止数据传输。这使您可以在不预先知道总大小的情况下发送/流式传输大量数据。但此选项在 HTTP 1.0 中不可用。

这解决了问题,但是如果 read() 在文件进行到一半时失败了怎么办?

您唯一能做的就是关闭套接字以发出传输终止的信号。如果您发送Content-Length 标头(或者在HTTP 1.1 分块的情况下,发送一个长度为0 的块),客户端将知道它何时收到了正确的文件结尾,并且过早关闭是错误的。但是如果没有这些信息,套接字关闭是发出传输结束信号的唯一方法,并且客户端无法知道它是成功还是错误(HTTP 1.1 确实有能力恢复中断的下载,但是HTTP 1.0 没有)。

由于内部错误,无法满足客户端请求,因此 500 状态代码是合适的,但我已经通过套接字发送了 200 OK 消息!

发送后您无法更改响应状态。但是,如果您让客户端知道它如何检测文件的正确结尾,它就会知道如何检测损坏的下载。

【讨论】:

  • 非常感谢您的回复!
猜你喜欢
  • 1970-01-01
  • 2013-08-25
  • 2020-07-15
  • 2016-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多