通过网络发送大量内容

Sending large content over Network

所以我想通过 tcp 发送大量内容,因此我使用 Network.Socket 库...

首先我有一个包装数据类型(示例!):

data Message =
        List [Int]
    |   String String
    |   END
    deriving stock Generic
    deriving anyclass Binary
    deriving Show
    deriving Eq

所以正常的工作流水线是:

--client
let bytestring = encode $ List [1..1000000] -- Lazzy ByteString
send socket $ toStrict bytestring
--server
Just msg <- recv socket 1024 
print $ decode $ fromStrict msg

问题是:我收到以下错误:

Data.Binary.Get.runGet at position 1017: not enough bytes CallStack (from HasCallStack): error, called at libraries/binary/src/Data/Binary/Get.hs:351:5 in binary-0.8.8.0:Data.Binary.Get ClientProjekt: Network.Socket.sendBuf: resource vanished (Broken pipe)

虽然

那么网络如何处理破坏解码功能的字节串?

主要问题是 recv socket 1024 仅从套接字请求 1024 字节,因此接收到的消息被截断了。此外 send 实际上并不保证将发送完整的字节串。您想改用 sendAll

我建议使用 Network.Socket.ByteString.Lazy 中的 sendAllgetContents 以避免将惰性字节串与严格字节串相互转换,并省去手动编写 recv循环。最小的服务器可能如下所示:

{-# LANGUAGE DeriveGeneric, DeriveAnyClass #-}

import GHC.Generics
import Data.Binary
import Network.Socket
import Network.Socket.ByteString.Lazy
import Prelude hiding (getContents)

data Message = List [Int]
  deriving (Generic, Binary)

main = do
  let hints = defaultHints
        { addrFlags = [AI_NUMERICHOST, AI_NUMERICSERV]
        , addrSocketType = Stream }
  addr:_ <- getAddrInfo (Just hints) (Just "127.0.0.1") (Just "8080")
  s <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
  bind s (addrAddress addr)
  listen s 1
  (s', _) <- accept s
  List xs <- decode <$> getContents s'
  close s'
  print $ sum xs

匹配的最小客户端可能如下所示:

{-# LANGUAGE DeriveGeneric, DeriveAnyClass #-}

import GHC.Generics
import Data.Binary
import Network.Socket
import Network.Socket.ByteString.Lazy

data Message = List [Int]
  deriving (Generic, Binary)

main = do
  let hints = defaultHints
        { addrFlags = [AI_NUMERICHOST, AI_NUMERICSERV]
        , addrSocketType = Stream }
  addr:_ <- getAddrInfo (Just hints) (Just "127.0.0.1") (Just "8080")
  s <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
  connect s (addrAddress addr)
  sendAll s (encode (List [1..1000000]))
  close s