我让人们使用Yaws的HTTP-GET下载文件。我已经在yaws_appmod_dav.erl中实现了,它运行正常。
case file:read(Fd,PPS) of
{ok,Data} when size(Data)<PPS ->
?DEBUG("only chunk~n"),
status(200,H,{content,Mimetype,Data});
{ok,Data} ->
?DEBUG("first chunk~n"),
spawn(fun() -> deliver_rest(Pid,Fd) end),
status(200,H,{streamcontent,Mimetype,Data});
eof ->
status(200,{content,"application/octet-stream",<<>>});
{error,Reason} ->
Response = [{'D:error',[{'xmlns:D',"DAV:"}],[Reason]}],
status(500,{xml,Response})
end;
我想在服务器上标记成功下载,即客户端已接受最后一个包。
我该怎么做?
一个小问题:在yaws的webdav-app中,yaws_api:stream_chunk_deliver在获取文件时使用yaws_api:stream_chunk_deliver_blocking。 (参见https://github.com/klacke/yaws/blob/master/src/yaws_appmod_dav.erl中的第449行)
为什么这不是问题?根据{{3}}“只要流的生产者比消费者更快,那就是WWW客户端,我们必须使用代码的同步版本。”我注意到两个版本都运行正常,它只是金额受影响的服务器上的内存?
答案 0 :(得分:0)
HTTP协议没有指定客户端通知服务器下载成功的方法。客户端要么获得由结果代码200
(或206
)确认的请求数据,要么得到它,并且在这种情况下,它会获得一个错误代码。然后客户端可以自由地重新请求该数据。所以,没有一种可靠的方式来实现你想要的东西。
您可以记录最后一块数据已发送到客户端并假设它已成功的事实,除非客户端重新请求该数据,在这种情况下您可以使之前的假设无效。
另外,请注意,HTTP规范允许在服务器发送带有Range header的GET请求时从服务器请求任何数据部分。请参阅此fusefs-httpfs实施中的示例以及此SO post中的更多信息。如果您不知道哪个使用Range标头的GET请求是最后一个请求(例如,客户端可以按顺序以块的形式下载整个文件),如何确定下载是否成功。
这也可以回答你的小问题。客户端通过从给定文件请求指定范围的字节来控制流。我不知道WebDAV协议的实现,但它可能不会立即请求整个文件,因此服务器可以以块的形式提供数据,而不会溢出客户端。 / p>
HTTP Range标头与TCP window size是分开的,它位于TCP协议级别(HTTP是在TCP之上实现的应用程序级协议)。假设客户端请求整个文件,服务器就像这样发送它。并不是说整个文件已经通过网络发送了。要发送的数据在内核中缓冲,并根据TCP窗口大小以块的形式发送。如果客户端仅使用Range标头请求部分数据,那么只有该部分将在内核中缓冲。