
The attached short program (compile with "ghc VServer.hs -o v -package net") is supposed to set up a server on port 15151, wait for a connection, read the first character from the connection, and print it out. Unfortunately if I test it, by running it, and starting up "telnet [machine] 15151" somewhere else, and then type some random text, EG "foo[RETURN]", it does not work. It looks as if the problem is that VServer.hs issues the command hSetBuffering handle (BlockBuffering (Just 4096)) on the connection, because when I change it to hSetBuffering handle NoBuffering the program works.
However this is not what I want to do!! Because setting NoBuffering on the handle is going to mean that when the Server *outputs* something, it will potentially be done very expensively character by character. How do I get block buffering on the Server's output, but not have input to the server held up?
Hmm. I rather think that hGetChar should always return a character immediately if there is one available, regardless of the buffering mode. Looking at the source, it appears that hGetLine behaves like this, as does lazy reading with hGetContents. I can't see any reason for waiting for the buffer to be completely full before returning anything. If you have a source tree handy, try the enclosed patch. If not, make a copy of hGetChar from the sources in libraries/base/GHC/IO.hs, apply the patch, and compile it separately (you'll need to import GHC.Handle explicitly, amongst other things). Cheers, Simon

I didn't notice this at first - but with hGetChar it prints nothing even after a return in telnet - it is better with the patch, as soon as you hit return in telnet the line is printed. Keean Simon Marlow wrote:
The attached short program (compile with "ghc VServer.hs -o v -package net") is supposed to set up a server on port 15151, wait for a connection, read the first character from the connection, and print it out. Unfortunately if I test it, by running it, and starting up "telnet [machine] 15151" somewhere else, and then type some random text, EG "foo[RETURN]", it does not work. It looks as if the problem is that VServer.hs issues the command hSetBuffering handle (BlockBuffering (Just 4096)) on the connection, because when I change it to hSetBuffering handle NoBuffering the program works.
However this is not what I want to do!! Because setting NoBuffering on the handle is going to mean that when the Server *outputs* something, it will potentially be done very expensively character by character. How do I get block buffering on the Server's output, but not have input to the server held up?
Hmm. I rather think that hGetChar should always return a character immediately if there is one available, regardless of the buffering mode. Looking at the source, it appears that hGetLine behaves like this, as does lazy reading with hGetContents. I can't see any reason for waiting for the buffer to be completely full before returning anything.
If you have a source tree handy, try the enclosed patch. If not, make a copy of hGetChar from the sources in libraries/base/GHC/IO.hs, apply the patch, and compile it separately (you'll need to import GHC.Handle explicitly, amongst other things).
Cheers, Simon

Simon Marlow wrote (snipped)
Hmm. I rather think that hGetChar should always return a character immediately if there is one available, regardless of the buffering mode. Looking at the source, it appears that hGetLine behaves like this, as does lazy reading with hGetContents. I can't see any reason for waiting for the buffer to be completely full before returning anything.
If you have a source tree handy, try the enclosed patch. If not, make a copy of hGetChar from the sources in libraries/base/GHC/IO.hs, apply the patch, and compile it separately (you'll need to import GHC.Handle explicitly, amongst other things). OK, applying the patch and dropping the patched hGetChar in (as per the attached file) seems to fix the problem. Is there any way of getting the same effect without setting NoBuffering/waiting for the next ghc release/changing every call by client and server to hGetChar in the program? If not I think I'll keep NoBuffering and wait for the next ghc release ..
Thanks, George -- Test program for server using GHC Socket library. module Main(main) where import GHC.Enum import GHC.Base import GHC.IOBase import GHC.Handle -- much of the real stuff is in here import GHC.Real import GHC.Num import GHC.Show import GHC.List import GHC.Exception ( ioError, catch ) import GHC.Conc import IO import Network main = do socket <- listenOn (PortNumber 15151) (handle,hostName,_) <- accept socket hSetBuffering handle (BlockBuffering (Just 4096)) putStr ("Accepted: "++hostName++"\n") c <- new_hGetChar handle putStrLn (show c) new_hGetChar :: Handle -> IO Char new_hGetChar handle = wantReadableHandle "hGetChar" handle $ \handle_ -> do let fd = haFD handle_ ref = haBuffer handle_ buf <- readIORef ref if not (bufferEmpty buf) then hGetcBuffered fd ref buf else do -- buffer is empty. case haBufferMode handle_ of LineBuffering -> do new_buf <- fillReadBuffer fd True (haIsStream handle_) buf hGetcBuffered fd ref new_buf BlockBuffering _ -> do new_buf <- fillReadBuffer fd True (haIsStream handle_) buf hGetcBuffered fd ref new_buf NoBuffering -> error "This can't happen" {- do -- make use of the minimal buffer we already have let raw = bufBuf buf r <- readRawBuffer "hGetChar" (fromIntegral fd) (haIsStream handle_) raw 0 1 if r == 0 then ioe_EOF else do (c,_) <- readCharFromBuffer raw 0 return c -} hGetcBuffered fd ref buf@Buffer{ bufBuf=b, bufRPtr=r, bufWPtr=w } = do (c,r) <- readCharFromBuffer b r let new_buf | r == w = buf{ bufRPtr=0, bufWPtr=0 } | otherwise = buf{ bufRPtr=r } writeIORef ref new_buf return c

You could try using lazy reading instead. Someting Like: module Main(main) where import IO import Network main = do socket <- listenOn (PortNumber 15151) (handle,hostName,_) <- accept socket hSetBuffering handle (BlockBuffering (Just 4096)) putStr ("Accepted: "++hostName++"\n") (c:_) <- hGetContents handle putStrLn (show c) Regards, Keean Schupke George Russell wrote:
Simon Marlow wrote (snipped)
Hmm. I rather think that hGetChar should always return a character immediately if there is one available, regardless of the buffering mode. Looking at the source, it appears that hGetLine behaves like this, as does lazy reading with hGetContents. I can't see any reason for waiting for the buffer to be completely full before returning anything.
If you have a source tree handy, try the enclosed patch. If not, make a copy of hGetChar from the sources in libraries/base/GHC/IO.hs, apply the patch, and compile it separately (you'll need to import GHC.Handle explicitly, amongst other things).
OK, applying the patch and dropping the patched hGetChar in (as per the attached file) seems to fix the problem. Is there any way of getting the same effect without setting NoBuffering/waiting for the next ghc release/changing every call by client and server to hGetChar in the program? If not I think I'll keep NoBuffering and wait for the next ghc release ..
Thanks,
George

Hmm, I just read jou dont want to change ever instance... In which case use the definition of hGetChar you just wrote, and change the import line to: import IO hiding (hGetChar) and it will use the local definition with no conflicts... Regards, Keean Schupke. Keean Schupke wrote:
You could try using lazy reading instead. Someting Like:
module Main(main) where
import IO import Network
main = do socket <- listenOn (PortNumber 15151) (handle,hostName,_) <- accept socket hSetBuffering handle (BlockBuffering (Just 4096)) putStr ("Accepted: "++hostName++"\n") (c:_) <- hGetContents handle putStrLn (show c)
Regards, Keean Schupke
George Russell wrote:
Simon Marlow wrote (snipped)
Hmm. I rather think that hGetChar should always return a character immediately if there is one available, regardless of the buffering mode. Looking at the source, it appears that hGetLine behaves like this, as does lazy reading with hGetContents. I can't see any reason for waiting for the buffer to be completely full before returning anything.
If you have a source tree handy, try the enclosed patch. If not, make a copy of hGetChar from the sources in libraries/base/GHC/IO.hs, apply the patch, and compile it separately (you'll need to import GHC.Handle explicitly, amongst other things).
OK, applying the patch and dropping the patched hGetChar in (as per the attached file) seems to fix the problem. Is there any way of getting the same effect without setting NoBuffering/waiting for the next ghc release/changing every call by client and server to hGetChar in the program? If not I think I'll keep NoBuffering and wait for the next ghc release ..
Thanks,
George
_______________________________________________ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
participants (3)
-
George Russell
-
Keean Schupke
-
Simon Marlow