Network, sClose

Glynn Clements glynn.clements at virgin.net
Wed Aug 11 13:08:00 EDT 2004


Jon Fairbairn wrote:

> > > Is recvFrom meant to be a one-shot function i.e. the socket is only closed
> > > when the process exits?
> > 
> > The implementation is:
> > 
> > > recvFrom host port = do
> > >  ip  <- getHostByName host
> > >  let ipHs = hostAddresses ip
> > >  s   <- listenOn port
> > >  let 
> > >   waiting = do
> > >      ~(s', SockAddrInet _ haddr)  <-  Socket.accept s
> > >      he <- getHostByAddr AF_INET haddr
> > >      if not (any (`elem` ipHs) (hostAddresses he))
> > >       then do
> > >          sClose s'
> > >          waiting
> > >       else do
> > > 	h <- socketToHandle s' ReadMode
> > >         msg <- hGetContents h
> > >         return msg
> > > 
> > >  message <- waiting
> > >  return message
> 
> This is rather more powerful than recvFrom in C, isn't it?

Yes, very much so.

> Perhaps it's misnamed: C's recvFrom deals with finite
> messages, but with the above I can receive an infinite list,
> which is the source of the problem, even if rather cool.

Well, C's recvfrom is normally only used with UDP, where you deal with
individual packets rather than connections. It's essentially recv()
but with the ability to retrieve the packet's source IP+port as well
as its payload. And recv() is just read() with some flags.

> > Note that the listening socket s is passed to accept then
> > forgotten about. If it was accessible, it would be
> > possible to either accept further connections on it, or to
> > close it. As it stands, it will remain open and unused for
> > the duration of the calling process.
> 
> So the problem is the same as with hGetContents in general,
> compounded by the calling programme not having access to the
> socket, so it can't close it even if it knows it's finished
> with the data.

No, it's worse than that. There are two sockets involved (the
listening socket plus the connection-specific socket), and you don't
get access to either of them.

AFAIK, you can live without the connection socket, provided that you
consume all of the data, and the connection is purely one-way (i.e. 
the client sends the data then closes the connection; it doesn't
expect the recipient to close its end).

The real problem is that the listening socket hangs around, tying up
the port. Actually, recvFrom should be able to close the listening
socket as soon as it has accepted the connection.

> > Right. If listenOn and accept are in Network, sClose should be in
> > there too. That would at least provide an API which is usable for the
> > simplest programs.
> 
> Agreed, and recvFrom seems to need to be something else,
> though the problem could be ameliorated by making
> withSocketsDo close
> any leftover sockets. You'd then have to use it for both
> Linux and Windows.

It would have to only close the sockets which were created via the
Haskell networking code. You wouldn't want it to close e.g. an X11
connection which Gtk+Hs/GLUT/etc were using, or stdin if that happened
to be a socket.

> > OTOH, the core problem with Network.recvFrom is
> > essentially that it appears to be a misguided attempt to
> > provide a symmetric counterpart to Network.sendTo. While
> > the low-level sendTo/recvFrom functions may be roughly
> > symmetric, at a higher level, the client and server ends
> > of a connection aren't at all symmetric.
> 
> Given that, recvFrom could :: HostName -> Socket -> IO
> String.  We'd have to call listenOn to get the socket, but
> that seems a small hardship compared to losing the use of
> the port.

If anything, it should probably just be:

	recvFrom :: Socket -> IO String

The behaviour of discarding connections until it gets one from the
specified hostname seems rather arbitrary, IMHO.

The more I think about it, the more that Network.recvFrom looks like
someone was hell-bent on producing a complement to Network.sendTo,
regardless of the benefit (or even sanity) of doing so.

Actually, if someone desperately wants a complement to sendTo, a
recvTo function would be more useful than recvFrom. I.e. connect to a
server and read data until the server closes the connection (usable
with services such as systat, netstat, daytime etc).

Similarly, sendFrom (i.e. accept a connection and send data) would be
just as useful as recvFrom.

-- 
Glynn Clements <glynn.clements at virgin.net>


More information about the Glasgow-haskell-users mailing list