Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/actionscript-3/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Http 为什么可以';打印hGetContents结果后,我是否使用hPutStr?_Http_Haskell_Network Programming - Fatal编程技术网

Http 为什么可以';打印hGetContents结果后,我是否使用hPutStr?

Http 为什么可以';打印hGetContents结果后,我是否使用hPutStr?,http,haskell,network-programming,Http,Haskell,Network Programming,我是新手,所以如果我做错了什么,请原谅我。我试图理解一个简单的服务器在Haskell中是如何工作的。我想我遗漏了一些关于hGetContents如何工作的非常简单或基本的东西 import Network import System.IO main = withSocketsDo $ do socket <- listenOn $ PortNumber 5002 (h, _, _) <- accept socket c <- hGetConte

我是新手,所以如果我做错了什么,请原谅我。我试图理解一个简单的服务器在Haskell中是如何工作的。我想我遗漏了一些关于hGetContents如何工作的非常简单或基本的东西

import Network 
import System.IO

main = withSocketsDo $ do
     socket <- listenOn $ PortNumber 5002
     (h, _, _) <- accept socket
     c <- hGetContents h
--   putStrLn c  -- doesn't work
--   putStrLn $ head $ lines c -- works!
--   putStrLn $ unlines $ take 2 $ lines c -- works!
--   putStrLn $ unlines $ take 3 $ lines c -- works!
--   putStrLn $ unlines $ take 6 $ lines c -- works!
     putStrLn $ unlines $ take 10 $ lines c -- doesn't work
     hPutStr h $ "HTTP/1.0 200 OK\r\nContent-Length: 5\r\n\r\nHello!\r\n"
     hClose h
导入网络
导入系统.IO
main=带库存的订单$do

socket当您在句柄上启动延迟读取时,您将放弃对句柄执行任何其他操作的权利,直到内容字符串完全强制执行为止,或者手动关闭句柄(此时尝试强制执行更多内容字符串将导致不良行为或错误)

TL;博士
在这种情况下,惰性I/O是不合适的。在套接字上进行延迟读取是合适的情况下,很可能是零指数。如果您愿意,您可以使用常规的严格I/O,或
导管
,或
管道
,或一些Haskell web框架,如Yesod或Scotty或其他各种竞争对手。

我试图重现您的问题。为此,我执行了您的代码,并使用nc向其发送请求:

printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11" | nc localhost 5002
正如预期的那样,服务器(您问题中的代码)打印出前10行,并在没有任何错误的情况下退出。客户端(nc)打印:

也没有出错就退出了

所以,一开始我不明白你的问题是什么,但后来我尝试发送一个较小的请求:

printf "1\n2\n3\n4\n5\n6\n" | nc localhost 5002
服务器打印了前6行,但没有退出。客户端也没有退出,所以我用Ctrl-C中断了它,然后服务器退出,出现“资源消失”错误

我想了想,这对我来说开始有意义了。我对懒惰IO的理解不太好,所以如果我的解释不清楚或不正确,如果有更好理解的人能够改进它,这将是有帮助的

让我们按照您的代码进行操作。第一:

(h, _, _) <- accept socket
c <- hGetContents h
在这里,您可以将懒惰、未评估的内容传递给另一个函数
take 10
take 10
将尝试计算列表中的前10个元素并返回它们,如果列表中的元素少于10个,则只返回所有元素。在
take 10
之后,我们有
putStrLn
unlines
,这两者都与懒惰完全相容

现在让我们假设客户机发送一个只有6行长的输入,然后开始等待响应。我们的服务器延迟接收内容并尝试打印前10行。首先,
take 10
函数愉快地使用前6行并将它们传递给
putStrLn。取消线
,然后会发生什么
take 10
不能仅仅完成它的输出,因为没有任何迹象表明它已经结束了。句柄仍然打开,字节仍然可以从客户端浮动到服务器,所以它只是等待更多的输入

可以通过运行以下程序来观察此行为:

nc localhost 5002
然后手动输入10行。输入将在您键入时逐行显示在服务器上。在您键入第10行后,服务器将以“Hello”消息响应

注:我猜您描述的行为是因为您的web浏览器在请求中发送了6到9行内容


要测试、调试和分析此类低级服务器,您应该使用简单的工具,如
nc
curl
,而不是web浏览器:)

调用
hGetContents
将句柄置于“半关闭”状态。在此点之后,不应对句柄执行任何操作。您应该只使用从
hGetContents
返回的字符串

简单地说,这里不要使用惰性I/O。您需要一次手动读取和写入一个字符串,因为时间很重要


一般来说,惰性I/O有点整洁,但它不适用于玩具示例以外的任何东西。

这个解释(特别是从“现在让我们假设客户机…”开始)是正确的。TCP连接的每个方向都可以独立关闭,如果服务器支持HTTP保持活动状态,则web浏览器在至少收到HTTP响应头之前不会关闭客户端->服务器方向。因此,最终会出现典型的死锁情况:服务器在收到10行请求或关闭接收通道之前无法发送响应,而浏览器在收到服务器的响应之前不会关闭响应。(继续)然而,这与懒惰的IO没有太大关系。您将从C程序中获得相同的行为,如
inth=accept(socket,…);对于(inti=0;i<10;i++){if(fgets(buf,size,h)){printf(“%s”,buf);}}fprintf(h,“…”)
如果您仔细考虑强制执行的请求量,可以使用
hGetContents
实现服务器。然而,由于HTTP是一种简单的基于行的协议,因此使用
hGetLine
和显式循环可能更容易。因此,单独使用
hPutStrLn c
是否也无法达到类似的效果,这意味着
hGetContents
永远不会发出结束的信号?
putStrLn $ unlines $ take 10 $ lines c
nc localhost 5002