我一直在使用conduit-extra
UNIX 包,它基本上允许使用 UNIX 域套接字轻松创建服务器,特别是使用runUnixServer
funciton。
问题是函数存在后并没有清理套接字文件,这意味着它需要手动清理。这是一个简单的示例,它基本上创建了一个回显服务器。
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
函数在终结器中忽略该值。