Sockets 使用ResourceT清理资源的正确方法是什么?
我一直在玩Sockets 使用ResourceT清理资源的正确方法是什么?,sockets,haskell,resources,conduit,Sockets,Haskell,Resources,Conduit,我一直在玩conductextra的UNIX包,它基本上允许使用UNIX域套接字轻松创建服务器,特别是使用 问题是,函数存在后,它不会清理套接字文件,这意味着需要手动清理。下面是一个简单的示例,它基本上创建了一个echo服务器 main :: IO () main = do let settings = serverSettings "foobar.sock" runUnixServer settings (\ad -> (appSource ad) $$ (appSink ad)
conductextra
的UNIX包,它基本上允许使用UNIX域套接字轻松创建服务器,特别是使用
问题是,函数存在后,它不会清理套接字文件,这意味着需要手动清理。下面是一个简单的示例,它基本上创建了一个echo服务器
main :: IO ()
main = do
let settings = serverSettings "foobar.sock"
runUnixServer settings (\ad -> (appSource ad) $$ (appSink ad))
我在谷歌上搜索了一下,发现处理资源的正确方法是使用包。尽管问题是资源中的大多数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))
不过,这种方法存在一个问题,至少就分配的文档所述:
这与调用分配然后注册释放操作几乎相同,但这可以正确处理异步异常的屏蔽
这是否意味着寄存器本身不处理异步异常?如果是这样,当runUnixServer
生成的一个处理程序(文档称它为每个客户端生成一个线程)引发错误时,这会是一个问题吗
我提出的第三个也是最后一个解决方案是使用allocate
,以确保异步异常得到正确处理(我不确定在这种情况下是否真的有必要)
但这真的是最好的解决方案吗?因为我正在创建一个我永远不会使用的值(返回1)
,然后使用const
函数在终结器中忽略该值。在解决resourcet
问题之前:
在这种情况下不需要resourcet
。您可以使用finally
函数进行类似操作,例如runUnixServer设置(\ad->…)
finallyremoveLink“foobar.sock”
这实际上看起来像是有问题的行为。导管中普遍接受的模式是,如果您分配了一个资源,您负责清理它。我没有编写unix套接字代码,因此作者可能有理由在这里采用不同的方式。但是值得打开一个bug报告
也就是说,您使用寄存器
的初始代码很好。我看到的唯一问题是,如果在创建foobar.sock
之前抛出异常,尽管我的finally
解决方案也易受此影响
关于allocate vs register的注释与如下代码有关:
handle <- openFile fp ReadMode
register $ hClose handle
handle感谢您的快速回复!
handle <- openFile fp ReadMode
register $ hClose handle