您可能需要考虑使用网络导管包。它将网络应用程序描述为具有两个“端点”的东西 - 一个接收器将数据推送到套接字中,一个从套接字读取数据的源:
type Application m = AppData m -> m ()
data AppData m Source -- ...
appSource :: AppData m -> Source m ByteStringSource
appSink :: AppData m -> Sink ByteString m ()
这清楚地分开了写作和阅读部分。现在,您可以使用这样的源和接收器做任何您喜欢的事情,甚至将每个传递到不同的线程并分别处理输入和输出。当然,它们中的每一个都只能读或写,这取决于你给它的端点。
如果您想强制执行单线程处理,您可以限制自己将程序组件实现为Conduit ByteString m ByteString
. 这样的管道可以很容易地变成Application
类似的
asApp :: MonadIO m => Conduit ByteString m ByteString -> Application m
asApp cond ad = appSource ad $= cond $$ appSink ad
但是管道只能使用 请求数据await
和写入输出yield
,否则无法访问任何类型的句柄并且永远不会看到它的任何端点,因此它不能在任何地方暴露或泄漏它们。