so I want to send huge stuff via tcp, therefore I use the Network.Socket library...
First of all I have a wrapper data type (Example!):
data Message =
List [Int]
| String String
| END
deriving stock Generic
deriving anyclass Binary
deriving Show
deriving Eq
so a normal work-pipeline would be:
--client
let bytestring = encode $ List [1..1000000] -- Lazzy ByteString
send socket $ toStrict bytestring
--server
Just msg <- recv socket 1024
print $ decode $ fromStrict msg
the problem with this is: I get the following error:
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)
Allthough
- just sending/reciving and printing without decoding on the server works fine.
- encoding -> toStrict -> fromStrict -> decoding: without sending over tcp works fine.
so what does the network do with the bytestring which breaks the decoding functionality?
CodePudding user response:
The main problem is that recv socket 1024
requests only 1024 bytes from the socket, so the received message is being truncated. Also send
doesn't actually guarantee that the full bytestring will be sent. You want to use sendAll
instead.
I'd advise using sendAll
and getContents
from Network.Socket.ByteString.Lazy
to avoid converting your lazy bytestring to and from a strict bytestring and to save you the trouble of manually writing a recv
loop. A minimal server might look like this:
{-# 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
and a matching minimal client might look like this:
{-# 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