Вот как бы я это сделал. Я не уверен, какая часть, по вашему мнению, нуждается в дополнительной служебной функции.
Сервер / отправитель:
import Data.Binary
import Data.Binary.Put
import qualified Data.ByteString.Lazy as BS
import Network.Run.TCP
import Network.Socket
import Network.Socket.ByteString.Lazy
sendWithLength :: Binary a => Socket -> a -> IO ()
sendWithLength s payload = do
let payloadBS = encode payload
let payloadLen = BS.length payloadBS
let payloadLenBS = runPut $ putInt32le $ fromIntegral payloadLen
sendAll s payloadLenBS
sendAll s payloadBS
handleClient :: Socket -> IO ()
handleClient s = do
sendWithLength s "Hello, World!"
sendWithLength s ([123, 45, 678] :: [Int])
main :: IO ()
main = runTCPServer Nothing "3000" handleClient
Клиент / получатель:
import Data.Binary
import Data.Binary.Get
import qualified Data.ByteString.Lazy as BS
import Data.Int
import Network.Run.TCP
import Network.Socket
import Network.Socket.ByteString.Lazy
-- Like recv, but doesn't return a partial result unless the socket reaches
-- EOF.
recvAll :: Socket -> Int64 -> IO BS.ByteString
recvAll s n = do
bytes <- recv s n
let len = BS.length bytes
if BS.null bytes || BS.length bytes == n
then
return bytes
else do
bytes' <- recvAll s (n - len)
return $ bytes <> bytes'
recvWithLength :: Binary a => Socket -> IO a
recvWithLength s = do
payloadLenBS <- recvAll s 4
let payloadLen = fromIntegral $ runGet getInt32le payloadLenBS
payloadBS <- recvAll s payloadLen
let payload = decode payloadBS
return payload
handleServer :: Socket -> IO ()
handleServer s = do
payload1 <- recvWithLength s
putStrLn payload1
payload2 <- recvWithLength s
print (payload2 :: [Int])
main :: IO ()
main = runTCPClient "127.0.0.1" "3000" handleServer
Кстати Network.Run.TCP
из network-run
пакет .