1

这是一个conduit组合器的示例,当从上游接收到完整的消息时,它应该在yield下游:

import qualified Data.ByteString as BS
import Data.Conduit
import Data.Conduit.Combinators
import Data.Conduit.Network

message :: Monad m => ConduitT BS.ByteString BS.ByteString m ()
message = loop
  where
    loop = await >>= maybe (return ()) go
    go x = if (BS.isSuffixOf "|" x)
        then yield (BS.init x) >> loop
        else leftover x

服务器代码本身如下所示:

main :: IO ()
main = do
  runTCPServer (serverSettings 5000 "!4") $ \ appData -> runConduit $
    (appSource appData)
    .| message
    .| (appSink appData)

telnet 127.0.0.1 5000发送任何消息后由于某种原因断开连接:

telnet 127.0.0.1 5000
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
123|
Connection closed by foreign host.

请指教,我在这里做错了什么?

更新

更重要的是,我在这里尝试做的是等待完成信号|,然后yield是下游的完整消息。下面是message组合器的演变:

message :: Monad m => ConduitT BS.ByteString BS.ByteString m ()
message = do
  minput <- await
  case minput of
    Nothing    -> return ()
    Just input -> do
      case BS.breakSubstring "|" input of
        ("", "")  -> return ()
        ("", "|") -> return ()
        ("", xs)  -> leftover $ BS.tail xs
        (x, "")   -> leftover x -- problem is in this leftover
        (x, xs)   -> do
          yield x
          leftover $ BS.tail xs
      message

我的想法是,如果上游组合器没有任何内容,则必须等到有东西出现,这样它才能向下游发送完整的消息。但是在上述组合器中的调用中,它conduit开始在 CPU 上旋转很多。leftovermessage

4

2 回答 2

1

最后发现有必要await而不是leftover在基本情况下。以下是工作message组合器的样子:

message :: Monad m => ConduitT BS.ByteString BS.ByteString m ()
message = do
  minput <- await
  case minput of
    Nothing    -> return ()
    Just input -> process input >> message
  where
    process input =
      case BS.breakSubstring "|" input of
        ("", "")  -> return ()
        ("", "|") -> return ()
        ("", xs)  -> leftover $ BS.tail xs
        (x, "")   -> do
          minput <- await
          case minput of
            Nothing -> return ()
            Just newInput -> process $ BS.concat [x, newInput]
        (x, xs)   -> do
          yield x
          leftover $ BS.tail xs

可能可以清理一些样板,但它可以工作。

于 2018-03-27T13:59:06.340 回答
0

打印xgo进行调试。

  ...
  go x = do
    liftIO (Prelude.print x)
    if ...

套接字接收一个以 结尾的字节串\r\n,因此您转到else终止会话的分支。

于 2018-03-27T12:12:29.023 回答