Haskell中ByteString解析和网络IO的混合 背景

Haskell中ByteString解析和网络IO的混合 背景,haskell,Haskell,我正在尝试为二进制网络协议编写一个客户端。 所有网络操作都是通过单个TCP连接执行的,因此从这个意义上讲 来自服务器的输入是一个连续的字节流。 然而,在应用层,服务器从概念上在服务器上发送数据包 流,并且客户机一直在读取,直到它知道已经收到数据包为止 在发送其自己的响应之前,请将其作为一个整体 完成这项工作所需的大量工作包括解析和生成 二进制数据,我正在使用data.Serialize模块 问题 服务器通过TCP流向我发送一个“数据包”。 数据包不一定由换行符终止,也不是预定的 尺寸。 它确实由

我正在尝试为二进制网络协议编写一个客户端。 所有网络操作都是通过单个TCP连接执行的,因此从这个意义上讲 来自服务器的输入是一个连续的字节流。 然而,在应用层,服务器从概念上在服务器上发送数据包 流,并且客户机一直在读取,直到它知道已经收到数据包为止 在发送其自己的响应之前,请将其作为一个整体

完成这项工作所需的大量工作包括解析和生成 二进制数据,我正在使用data.Serialize模块

问题 服务器通过TCP流向我发送一个“数据包”。 数据包不一定由换行符终止,也不是预定的 尺寸。 它确实由预定数量的字段组成,字段通常从 用一个4字节的数字描述该字段的长度。 在Data.Serialize的帮助下,我已经有了解析ByteString的代码 将此数据包的版本转换为更易于管理的类型

我希望能够使用以下属性编写一些代码:

  • 解析只定义一次,最好是在序列化实例中。 我不希望在IO monad中进行额外的解析来读取正确的字节数
  • 当我试图解析一个给定的数据包,但并不是所有的字节都已到达时,懒惰 IO将只等待额外的字节到达
  • 相反,当我试图解析一个给定的数据包时,它的所有字节都已到达 IO不再阻塞。也就是说,我想读足够的流 从服务器解析我的类型并形成一个响应以发送回。如果IO 即使在到达足够的字节来解析我的类型之后,也会阻塞 服务器将陷入死锁,每个服务器都在等待来自另一个服务器的更多数据
  • 在发送我自己的响应之后,我可以通过解析下一个类型来重复这个过程 我期望从服务器得到的数据包的数量
  • 所以简而言之,, 是否可以结合使用我当前的ByteString解析代码 使用惰性IO从网络上准确读取正确的字节数?

    我试过的 我尝试将lazy ByTestStreams与我的数据结合使用 因此:

    导入网络
    导入系统.IO
    将限定的Data.ByteString.Lazy作为L导入
    导入数据。序列化
    数据MyType
    实例序列化MyType
    main=带库存的订单$do
    
    您的解析器出了问题,它太急切了。由于某种原因,它很可能需要消息后面的下一个字节
    hGetContents
    from
    bytestring
    不会阻止等待整个区块。它在内部使用
    hGetSome

    我创建了一个简单的测试用例。服务器每秒发送一次“hello”:

    import Control.Concurrent
    import System.IO
    import Network
    
    port :: Int
    port = 1234
    
    main :: IO ()
    main = withSocketsDo $ do
      s <- listenOn $ PortNumber $ fromIntegral port
      (h, _, _) <- accept s
    
      let loop :: Int -> IO ()
          loop 0 = return ()
          loop i = do
            hPutStr h "hello"
            threadDelay 1000000
            loop $ i - 1
      loop 5
    
      sClose s
    
    导入控制。并发
    导入系统.IO
    导入网络
    端口::Int
    端口=1234
    main::IO()
    main=带库存的订单$do
    
    s+1非常好而且令人信服的测试用例。奇怪的是,这不是一个额外的字节,我预计在结束的数据包,而是一个领域在中东,似乎是有问题的…
    import Control.Concurrent
    import System.IO
    import Network
    
    port :: Int
    port = 1234
    
    main :: IO ()
    main = withSocketsDo $ do
      s <- listenOn $ PortNumber $ fromIntegral port
      (h, _, _) <- accept s
    
      let loop :: Int -> IO ()
          loop 0 = return ()
          loop i = do
            hPutStr h "hello"
            threadDelay 1000000
            loop $ i - 1
      loop 5
    
      sClose s
    
    import qualified Data.ByteString.Lazy as BSL
    import System.IO
    import Network
    
    port :: Int
    port = 1234
    
    main :: IO ()
    main = withSocketsDo $ do
      h <- connectTo "localhost" $ PortNumber $ fromIntegral port
      bs <- BSL.hGetContents h
      BSL.putStrLn bs
      hClose h