【问题标题】:Pipes get Network.Socket.ByteString.recv: failed (Unknown error)管道获取 Network.Socket.ByteString.recv:失败(未知错误)
【发布时间】:2014-12-06 23:24:03
【问题描述】:

也许做事的方式很愚蠢,但就是这样。我想将 HTTP 请求发送/接收与处理响应分开。

import Pipes
import qualified Pipes.HTTP as HTTP
import Pipes.Core
import qualified Pipes.ByteString as PB
import Network.Socket (withSocketsDo)

fetch m url = do
  req <- lift $ HTTP.parseUrl url
  resp <- lift $ HTTP.withHTTP req m return
  url' <- respond $ HTTP.responseBody resp
  fetch m url'

client :: Client String (Producer PB.ByteString IO ()) IO ()
client = do
          b <- request "http://www.google.com"
          lift $ runEffect $ b >-> PB.stdout

main = withSocketsDo $ HTTP.withManager HTTP.tlsManagerSettings $ \m ->
     runEffect $ fetch m +>> client

似乎合法。但是我得到了部分响应打印和“Network.Socket.ByteString.recv:失败(未知错误)”。我需要做些什么不同的事情?

【问题讨论】:

标签: haskell haskell-pipes


【解决方案1】:

错误是这部分:

HTTP.withHTTP req m return

有一个约定(不是由类型强制执行的),当一个函数以单词with 开头时,你不能让它分配的资源从它所包含的块中逃逸。原因是这些withXXX 函数在块完成时会释放资源,因此资源在该点之后无效。

所以发生的情况是,您尝试 return 来自 withHTTP 块的响应,但是通过下一行代码,响应已经被处理掉了。解决方案是使用pipes-safe,它允许您使用Pipes.Safe.bracket 在管道内安全地获取资源。您所要做的就是提供一个打开和关闭操作:

fetch m url = do
    req  <- lift $ HTTP.parseUrl url
    url' <- bracket openSomething closeSomething $ \resp -> do
        respond $ HTTP.responseBody resp
    fetch m url'

这将确保resprespond 完成之前不会被释放。

【讨论】:

  • 谢谢。有没有一种标准的方法来找出打开/关闭什么? (在这种情况下,我确实发现withHTTPwithResponse 在里面,然后withResponse 解释说)
  • 通常它们将在与with 函数相同的模块中提供。另外,检查resourcet 包,它提供了Resource 类型。该类型允许您将 openclose 操作捆绑在一起,以便您以后可以再次恢复它们。
猜你喜欢
  • 1970-01-01
  • 2017-11-19
  • 1970-01-01
  • 2015-04-08
  • 2020-05-07
  • 2020-01-12
  • 1970-01-01
  • 2013-07-21
  • 1970-01-01
相关资源
最近更新 更多