hGetBuf (or something related) broken for 6.2 with sockets
George Russell
ger at informatik.uni-bremen.de
Thu Dec 18 13:44:58 EST 2003
I have just installed ghc6.2 on Linux. (I had to compile it from source because the
binaries insist on a glibc version we don't have.)
The attached module contains two functions (serverMain) and (clientMain).
clientMain opens a connection (to localhost) and sends some data along it,
then executes hFlush.
serverMain receives this data. They should display identical data.
This should be run by (1) compiling the code using
> ghc Server.hs -c
(2) starting up ghci in this directory, twice, in separate terminal windows.
(3) in both ghci's doing
> :module Server
(4) in one ghci doing
> serverMain
(5) in the other ghci doing
> clientMain
What happens is
(a) the serverMain ghci displays "Iterating" several times. This is because
hGetBuf appears to be terminating prematurely when there is still data to come
on the socket. This is a pain (especially as I took several hours finding this
was why my program didn't work), but at least it can be worked around, and the code
in the module does this.
(b) The server module only gets part of the data. In fact for me it comes to a stop
with
[239][240][241][242][243Iterating
despite there being more data to come. (And despite the fact that the client has
done hFlush).
I don't know any way of working around (b), so I suspect that means ghc6.2 is unusable
for us. What a pity no development snapshot was made for 6.2 shortly before its
release, as it might have been possible for me to discover this bug in time for it
to be fixed in 6.2. (I did try to test the 6.3 development snapshot but was
grounded by the instances bug I've reported elsewhere.)
-------------- next part --------------
module Server where
import Char
import IO
import Random
import Monad
import Network
import GHC.IO(hPutBuf,hGetBuf)
import Foreign.C.Types
import Foreign.ForeignPtr
import Foreign.Marshal.Array
import Foreign.Marshal.Alloc
import Foreign.Ptr
maxLen = (2000 :: Int)
port = PortNumber 11394
host = "localhost"
writeInt :: Handle -> Int -> IO ()
writeInt handle i = hPutStrLn handle (show i)
readInt :: Handle -> IO Int
readInt handle =
do
l <- hGetLine handle
return (read l)
runClient :: Ptr CChar -> Handle -> IO ()
runClient ptr handle =
do
mapM_
(\ _ ->
writeOut ptr maxLen handle
>> mapM_
(\ toWrite -> writeOut ptr toWrite handle
)
[1..255]
)
[1..4]
hFlush handle
writeOut :: Ptr CChar -> Int -> Handle -> IO ()
writeOut ptr toWrite handle =
do
putStr ("["++show toWrite)
hFlush stdout
writeInt handle toWrite
hPutBuf handle ptr toWrite
putStr ("]")
hFlush stdout
getChars :: Handle -> Ptr CChar -> Int -> IO ()
getChars handle ptr 0 = return ()
getChars handle ptr toRead =
do
read <- hGetBuf handle ptr toRead
if (read == 0)
then
error ("Unexpected EOF") else return ()
if read < toRead
then
putStrLn "Iterating" >> hFlush stdout >>
getChars handle (plusPtr ptr read) (toRead - read)
else
return ()
readIn :: Ptr CChar -> Handle -> IO ()
readIn ptr handle =
do
toRead <- readInt handle
putStr ("["++show toRead)
hFlush stdout
getChars handle ptr toRead
putStr "]"
hFlush stdout
runServer :: Ptr CChar -> Handle -> IO ()
runServer ptr handle =
do
readIn ptr handle
runServer ptr handle
clientMain =
do
ptr <- mallocBytes maxLen
handle <- connectTo host port
runClient ptr handle
serverMain =
do
ptr <- mallocBytes maxLen
socket <- listenOn port
(handle,hostName,_) <- accept socket
runServer ptr handle
More information about the Glasgow-haskell-bugs
mailing list