
Dear Haskellers. I would like to build simple UDP server application. To parse a packet, I decide to use Data.Binary as followings: data Packet = Packet { foo :: Word16, bar :: Word16, baz :: Word32 } deriving (Show, Eq) instance Binary Packet where get = do foo <- get :: Get Word16 bar <- get :: Get Word16 baz <- get :: Get Word32 return (Packet foo bar baz) -- omitting put because we're now just receiving only serveUDP port handlerfunc = withSocketsDo $ do ... procMessages sock where procMessages sock = do (msg, _, addr) <- recvFrom sock 10240 handlerfunc addr msg procMessages sock myHandler addr msg = do putStrLn $ decode (Data.ByteString.Lazy.Char8.Pack msg) run = serveUDP "8080" myHandler But, running it and sending sample udp packet results in following exception. *Main> run Loading package syb ... linking ... done. Loading package base-3.0.3.1 ... linking ... done. Loading package array-0.2.0.0 ... linking ... done. Loading package containers-0.2.0.1 ... linking ... done. Loading package bytestring-0.9.1.4 ... linking ... done. Loading package parsec-2.1.0.1 ... linking ... done. Loading package network-2.2.1 ... linking ... done. Loading package binary-0.5.0.1 ... linking ... done. *** Exception: too few bytes. Failed reading at byte position 9 *Main> Why and what can I do for this? Thanks in advance. Chul-Woong Yang

2009/7/28 Yang, Chul-Woong
*** Exception: too few bytes. Failed reading at byte position 9 *Main>
Why and what can I do for this? Thanks in advance.
The Get monad is complaining that you are trying to read more than 8 bytes from a buffer of length 8. Presumably you are sending packets of that size? If you want to handle such errors (and you should), you could either first test the length of the incoming message or use exception handling to catch the exception in myHandler. - Björn

On Wed, Jul 29, 2009 at 09:19:39AM +0900, Yang, Chul-Woong wrote:
data Packet = Packet { foo :: Word16, bar :: Word16, baz :: Word32 } deriving (Show, Eq)
instance Binary Packet where get = do foo <- get :: Get Word16 bar <- get :: Get Word16 baz <- get :: Get Word32 return (Packet foo bar baz) -- omitting put because we're now just receiving only
By the way, I have nothing to contribute towards solving your actual problem, but I wanted to point out that you can write this Binary instance much more simply. First of all, you can just write
instance Binary Packet where get = do foo <- get bar <- get baz <- get return (Packet foo bar baz)
and through the magic of type inference, Haskell will figure out the right instances to use based on the fact that you use foo, bar, and baz as arguments to Packet, which expects certain types. (Although having the type signatures there as documentation is not a terrible idea.) But actually, we can do even better:
import Control.Applicative
instance Binary Packet where get = Packet <$> get <*> get <*> get
Amazing! =) This is exactly the sort of thing Applicative is for. It lets us program in an "applicative" style where we apply functions to arguments, where the arguments are computed in some sort of context that may have "effects". Monads give us the power to decide which monadic actions to run next based on the results of a previous action, but we don't need that power here: we are always going to run 'get' three times and put the results in a Packet. Using Applicative lets us avoid giving names to the results of the calls to get. -Brent
participants (3)
-
Bjoern Brandenburg
-
Brent Yorgey
-
Yang, Chul-Woong