通过网络发送大量内容
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)
虽然
- 只需 sending/reciving 并且在服务器上不解码就可以正常打印。
- 编码 -> toStrict -> fromStrict -> 解码:无需通过 tcp 发送即可正常工作。
那么网络如何处理破坏解码功能的字节串?
主要问题是 recv socket 1024
仅从套接字请求 1024 字节,因此接收到的消息被截断了。此外 send
实际上并不保证将发送完整的字节串。您想改用 sendAll
。
我建议使用 Network.Socket.ByteString.Lazy
中的 sendAll
和 getContents
以避免将惰性字节串与严格字节串相互转换,并省去手动编写 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
所以我想通过 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)
虽然
- 只需 sending/reciving 并且在服务器上不解码就可以正常打印。
- 编码 -> toStrict -> fromStrict -> 解码:无需通过 tcp 发送即可正常工作。
那么网络如何处理破坏解码功能的字节串?
主要问题是 recv socket 1024
仅从套接字请求 1024 字节,因此接收到的消息被截断了。此外 send
实际上并不保证将发送完整的字节串。您想改用 sendAll
。
我建议使用 Network.Socket.ByteString.Lazy
中的 sendAll
和 getContents
以避免将惰性字节串与严格字节串相互转换,并省去手动编写 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