Use*_*ror 2 haskell network-programming http
我是stackoverflow的新手,请原谅我,如果我做错了什么.我试图了解一个简单的服务器如何在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
Run Code Online (Sandbox Code Playgroud)
运行程序后,我通过Web浏览器导航到http:// localhost:5002.问题似乎是,根据我解析了句柄内容的程度,我最终无法发送响应.我希望能够在发送回复之前解析请求.我在代码中评论了有效的案例和没有的案例.Hoogle说,对于hGetContents(懒惰),句柄在被阅读时是"半封闭的".我是否误解了懒惰,或者一旦开始解析其内容,我应该考虑关闭句柄吗?
我得到的错误是"hPutChar:资源消失(断管)." 谢谢你的帮助.
我试图重现你的问题.为此,我执行了您的代码并使用nc向它发送请求:
printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11" | nc localhost 5002
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,服务器(来自您的问题的代码)打印出前10行并退出而没有任何错误.客户(nc)打印:
HTTP/1.0 200 OK
Content-Length: 5
Hello!
Run Code Online (Sandbox Code Playgroud)
并且也没有错误地退出.
所以,起初我无法理解你的问题是什么,但后来我尝试发送一个较小的请求:
printf "1\n2\n3\n4\n5\n6\n" | nc localhost 5002
Run Code Online (Sandbox Code Playgroud)
服务器打印前6行并没有退出.客户端也没有退出,所以我用Ctrl-C打断它,之后服务器退出"资源消失"错误.
我采取了一些思考,它开始对我有意义.我不太了解懒惰的IO太好了,所以如果我的解释不清楚或不正确,如果有更好理解的人会改进它会有所帮助.
让我们按照你的代码.第一:
(h, _, _) <- accept socket
c <- hGetContents h
Run Code Online (Sandbox Code Playgroud)
你打开一个手柄并阅读它的内容.请注意,句柄是惰性的,您获得的内容也是惰性的.当我们说某些东西是懒惰的时候,我们的意思是它可以在没有被评估的情况下被传递(它通常被称为"按名称调用"和"按值调用").
现在:
putStrLn $ unlines $ take 10 $ lines c
Run Code Online (Sandbox Code Playgroud)
在这里,您将懒惰的,未评估的内容传递给另一个函数take 10.take 10将尝试评估列表的前10个元素并返回它们,如果列表中的元素少于10个,它将简单地返回所有元素.经过take 10我们putStrLn和unlines这两者完美懒惰兼容.
现在让我们说客户端发送的输入只有6行,然后开始等待响应.我们的服务器懒洋洋地接收内容并尝试打印前10行.首先,take 10函数愉快地消耗前6行并将它们传递给putStrLn . unlines,然后会发生什么?take 10不能只是完成它的输出,因为绝对没有迹象表明它是结束.句柄仍然是打开的,字节仍然可以从客户端浮动到服务器,所以它只是等待更多的输入.
运行以下命令可以观察到此行为:
nc localhost 5002
Run Code Online (Sandbox Code Playgroud)
并手动输入10行.输入将在您键入时逐行显示在服务器上.键入第10行后,服务器将以"Hello"消息响应.
PS:我想你所描述的行为是因为你的网页浏览器发送了6到9行的请求.
要测试,调试和分析这种低级服务器,您应该使用简单的工具nc,curl而不是Web浏览器:)