Sockets again

Glynn Clements glynn.clements@virgin.net
Tue, 29 Apr 2003 22:22:32 +0100


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 <glynn.clements@virgin.net>