【发布时间】:2014-05-21 23:46:58
【问题描述】:
我一直在玩 conduit-extra 的 UNIX 包,它基本上允许使用 UNIX 域套接字轻松创建服务器,特别是使用 runUnixServer funciton。
问题是函数存在后并没有清理socket文件,这意味着需要手动清理。这是一个简单的例子,它基本上创建了一个回显服务器。
main :: IO ()
main = do
let settings = serverSettings "foobar.sock"
runUnixServer settings (\ad -> (appSource ad) $$ (appSink ad))
我用谷歌搜索了一下,发现这里处理资源的正确方法是使用resourcet 包。虽然问题是资源中的大多数 API 都希望我自己分配资源,但 runUnixSever 的情况并非如此,它不会返回任何内容。
一开始我以为可以用register,注册一个删除文件的函数,比如下面
main :: IO ()
main = runResourceT $ do
register $ removeLink "foobar.sock"
let settings = serverSettings "foobar.sock"
liftIO $ runUnixServer settings (\ad -> (appSource ad) $$ (appSink ad))
但这种方法存在问题,至少就allocate 的文档而言:
这几乎与调用分配然后注册释放操作相同,但是这可以正确处理异步异常的屏蔽。
这是否意味着register 本身不处理异步异常?如果是这样,当runUnixServer 生成的处理程序之一(文档说它为每个客户端生成一个线程)引发错误时,这是否会成为问题?
我想出的第三个也是最后一个解决方案是使用allocate,以确保正确处理异步异常(我不确定在这种情况下是否真的有必要)。
main :: IO ()
main = runResourceT $ do
allocate (return 1) (const $ removeLink "foobar.sock")
let settings = serverSettings "foobar.sock"
liftIO $ runUnixServer settings (\ad -> (appSource ad) $$ (appSink ad))
但这真的是最好的解决方案吗?因为我正在创建一个我永远不会使用 (return 1) 的值,然后使用 const 函数在终结器中忽略该值。
【问题讨论】:
标签: sockets haskell resources conduit