
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? The same thing seems to happen with client Handles by the way. -- Test program for server using GHC Socket library. 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 <- hGetChar handle putStrLn (show c)

Hi, The problem is not with the haskell, but with telnet, which uses line buffered output itself. Try the following: 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 <- hGetLine handle putStrLn (show c) telnet to this, type a line and hit return ... should print the line. Regards, Keean Schupke George Russell 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?
The same thing seems to happen with client Handles by the way.
------------------------------------------------------------------------
-- Test program for server using GHC Socket library. 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 <- hGetChar handle putStrLn (show c)

Keean Schupke wrote:> Hi,
The problem is not with the haskell, but with telnet, which uses line buffered output itself.
Try the following:
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 <- hGetLine handle putStrLn (show c)
telnet to this, type a line and hit return ... should print the line.
I presume this is the same program I sent. I *did* hit return, so I don't think that's the problem.

George Russell 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?
Try using the low-level accept function in Network.Socket, calling
socketToHandle twice to get separate read/write streams, e.g.
accept2 :: Socket -> IO (Handle, Handle, HostName, PortNumber)
accept2 sock = do
~(sock', (SockAddrInet port haddr)) <- Network.Socket.accept sock
(HostEntry peer _ _ _) <- getHostByAddr AF_INET haddr
handle'r <- socketToHandle sock' ReadMode
handle'w <- socketToHandle sock' WriteMode
return (handle'r, handle'w, peer, port)
[This is untested, so I may have overlooked something.]
More generally, many of the higher-level I/O functions have been
over-simplified to the point where they're unsuitable for real-world
use.
--
Glynn Clements

More generally, many of the higher-level I/O functions have been over-simplified to the point where they're unsuitable for real-world use.
would it be possible (i.e., would you or someone else who's already been through the problems be willing;-) to document the known problems with the high-level network functions? Cheers, Claus -- Haskell Communities and Activities Report (May 2003 edition) Contributions are due in by the end of THIS week! http://www.haskell.org/communities/

I think you are refering to problems with the semantics of the high level network IO, but I have to say the problems I have encountered have maily to do with exception-handlers missing in connectTo, accept, some low level socket functions from Handle.hs (finalizer on the wrong side, missing exception handler in hClose) etc... I am using a version of the libraries with all these problems patched (most of the fixes should have been in 5.04.3, but for one reason or another some of them did not make it)... With these patched versions I have been working on both client and server modules accross multiple binary and ascii protocols, and I normaly use hGetContents for lazy reading, and hPutStr hPutChar etc for writing... very much real world use - and I find them perfectly useful... Infact I see little need to go deeper into the networking code. I would be interested to know why these functions are not useful? Regards, Keean Schupke. C.Reinke wrote:
More generally, many of the higher-level I/O functions have been over-simplified to the point where they're unsuitable for real-world use.
would it be possible (i.e., would you or someone else who's already been through the problems be willing;-) to document the known problems with the high-level network functions?
Cheers, Claus
-- Haskell Communities and Activities Report (May 2003 edition) Contributions are due in by the end of THIS week! http://www.haskell.org/communities/ _______________________________________________ Glasgow-haskell-users mailing list Glasgow-haskell-users@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

C.Reinke wrote:
More generally, many of the higher-level I/O functions have been over-simplified to the point where they're unsuitable for real-world use.
would it be possible (i.e., would you or someone else who's already been through the problems be willing;-) to document the known problems with the high-level network functions?
I wasn't referring to network functions specifically, but I/O
functions generally.
One key problem with the higher-level I/O functions (including
networking) is the use of the Handle type (which seems to be roughly
analogous to ANSI C's "FILE*").
While this is portable, it's too limited to be of use to non-trivial
programs. ANSI I/O is fine for simple programs (read file, write
file), but once you start getting into writing interactive programs or
complex networking daemons, you tend to have to start using low-level
features (tty control, buffering, select(), signal handling etc).
The main problem with high-level interfaces (generally, not just in
Haskell) is that they're fine so long as they do everything that you
require. But as soon as you need to do something which the interface
doesn't allow for, not only do you have to find the appropriate
low-level interface but, unless you can avoid the high-level interface
altogether, you also need to acquire a thorough understanding of
exactly how the two relate to each other.
E.g. using both an ANSI stream (FILE*) and its descriptor in the same
program is likely to produce unexpected (and undesirable) behaviour
unless you have a reasonable understanding of exactly how the ANSI I/O
stuff works internally. If you find that you have to use descriptors
for at least some operations, it's often simpler to just not use the
ANSI interface at all.
--
Glynn Clements
participants (4)
-
C.Reinke
-
George Russell
-
Glynn Clements
-
Keean Schupke