I've been struggling with getting network and binary to play nicely together and I think it might have something to do with strict vs. lazy bytestrings but I don't know for sure. I have written several type-correct programs that utterly fail at run-time: either the program consumes one byte then hangs and does nothing... or I get it to consume a number of bytes, hang and do nothing or I get it to wait and consume all of the input without parsing anything but that also fails as well.
I need to consume 9 bytes of input, exactly, and parse it. According to the protocol the first byte is a char and the other 8 are two unsigned 32 bit, big-endian integers. Simple enough, right?
I've been banging my head against this problem of buffering up 9 bytes of data to pass off to my binary parser. Is there a library I'm missing that makes writing parsers with binary and reading data from socket IO straight-forward?
I think I'm missing a streaming abstraction. This minimal example:
{-# LANGUAGE OverloadedStrings #-}moduleProtohacker.Servers.Proto2whereimportControl.MonadimportData.ByteString(ByteString)importqualifiedData.ByteStringasBimportNetwork.Run.TCPimportNetwork.SocketimportNetwork.Socket.ByteStringstart::IO()start=dorunTCPServerNothing"3000"tickerServertickerServer::Socket->IO()tickerServers=domsgs<-recvExactlys9forM_msgs$\msg->doprintmsg-- | Buffer all content on the socket and return it to the caller in-- `maxBytes` chunks.recvExactly::Socket->Int->IO[(ByteString,SockAddr)]recvExactlysocketmaxBytes=undefined
Basically needs to buffer up 9 byte chunks using IO into a list. If you try to implement recvExactly using the recvFrom function from Network.Socket.ByteString you can tell it to receive 9 bytes but it will only guarantee that it will receive up to and including 9 bytes. So if you try to recur successive calls to build up a buffer you'll need a way to maintain that buffering state or otherwise lazily hand off chunks to the list somehow :thinking:
For example, on the first call recvFrom returns immediately with a single byte and we recur since it was not empty. On the recur we get all 9 bytes. If we're threading through a ByteString argument as our buffer and we combine the 1 from before and 9 bytes now we have 10 bytes, 9 of which we want to pass on to the caller and the rest we hold on to and recur again.
I've been struggling with getting
network
andbinary
to play nicely together and I think it might have something to do with strict vs. lazy bytestrings but I don't know for sure. I have written several type-correct programs that utterly fail at run-time: either the program consumes one byte then hangs and does nothing... or I get it to consume a number of bytes, hang and do nothing or I get it to wait and consume all of the input without parsing anything but that also fails as well.I need to consume 9 bytes of input, exactly, and parse it. According to the protocol the first byte is a char and the other 8 are two unsigned 32 bit, big-endian integers. Simple enough, right?
I've been banging my head against this problem of buffering up 9 bytes of data to pass off to my
binary
parser. Is there a library I'm missing that makes writing parsers withbinary
and reading data from socket IO straight-forward?Is there any code you could share to test with?
I think I'm missing a streaming abstraction. This minimal example:
Basically needs to buffer up 9 byte chunks using
IO
into a list. If you try to implementrecvExactly
using therecvFrom
function fromNetwork.Socket.ByteString
you can tell it to receive 9 bytes but it will only guarantee that it will receive up to and including 9 bytes. So if you try to recur successive calls to build up a buffer you'll need a way to maintain that buffering state or otherwise lazily hand off chunks to the list somehow :thinking:For example, on the first call
recvFrom
returns immediately with a single byte and we recur since it was not empty. On the recur we get all 9 bytes. If we're threading through aByteString
argument as our buffer and we combine the 1 from before and 9 bytes now we have 10 bytes, 9 of which we want to pass on to the caller and the rest we hold on to and recur again.I don't know how to do a lazy list embedded in
IO
though :sweat_smile: Although maybe this is already solved in something likeconduit
? :thinking:Especially since list is probably not the right approach if the input size from the client is large :sweat_smile: