
-----Original Message----- From: Glynn Clements [mailto:glynn.clements@virgin.net]
However, even if sClose was exported, that wouldn't be of any help in Jon's case, as neither of the sockets which recvFrom creates are visible outside of recvFrom.
Ahh, OK. I haven't used recvFrom/sendTo yet... (trying it now) ... When I try Jon's example with 6.2.1 (Win XP) I don't get the same error; it works twice and then hangs (my networking code would hang if I tried to re-use a socket that hadn't been properly closed). Is recvFrom meant to be a one-shot function i.e. the socket is only closed when the process exits? Jon's second example uses listenOn/accept and handles, which is also what I used:
do sock <- listenOn$PortNumber 7607; (hdl,host,port)<- accept sock; s<-IO.hGetContents hdl; putStr$s; IO.hClose hdl; Network.Socket.sClose sock
Network.Socket.sClose is obviously useful here, so don't you think it would be a good idea to put it in Network? I don't see why including sClose would imply that you should start exposing other low-level stuff. AFAICT, it is the one little thing that's missing from Network that makes writing simple networking code possible. There's a lack of symmetry (closure?): you can create a socket with Network.listenOn, but there is no corresponding close function in Network. ----------------------------------------- ***************************************************************** Confidentiality Note: The information contained in this message, and any attachments, may contain confidential and/or privileged material. It is intended solely for the person(s) or entity to which it is addressed. Any review, retransmission, dissemination, or taking of any action in reliance upon this information by persons or entities other than the intended recipient(s) is prohibited. If you received this in error, please contact the sender and delete the material from any computer. *****************************************************************

Bayley, Alistair wrote:
However, even if sClose was exported, that wouldn't be of any help in Jon's case, as neither of the sockets which recvFrom creates are visible outside of recvFrom.
Ahh, OK. I haven't used recvFrom/sendTo yet... (trying it now) ... When I try Jon's example with 6.2.1 (Win XP) I don't get the same error; it works twice and then hangs (my networking code would hang if I tried to re-use a socket that hadn't been properly closed).
Odd.
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
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. A subsequent call to recvFrom would call listenOn again, attempting to create another listening socket on the same address and port. Obviously, that should fail so long as the original socket still exists (the kernel doesn't know that the original socket can't ever be used again).
Jon's second example uses listenOn/accept and handles, which is also what I used:
do sock <- listenOn$PortNumber 7607; (hdl,host,port)<- accept sock; s<-IO.hGetContents hdl; putStr$s; IO.hClose hdl; Network.Socket.sClose sock
Network.Socket.sClose is obviously useful here, so don't you think it would be a good idea to put it in Network? I don't see why including sClose would imply that you should start exposing other low-level stuff. AFAICT, it is the one little thing that's missing from Network that makes writing simple networking code possible.
There's a lack of symmetry (closure?): you can create a socket with Network.listenOn, but there is no corresponding close function in Network.
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.
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.
--
Glynn Clements

On 2004-08-11 at 14:19BST Glynn Clements wrote:
Bayley, Alistair 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? 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.
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.
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.
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. [1] What's the "Do" doing there anyway? You end up writing withSocketsDo$do, and we could do without the Do$do. -- Jón Fairbairn Jon.Fairbairn@cl.cam.ac.uk

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

"Jon Fairbairn"
[1] What's the "Do" doing there anyway? You end up writing withSocketsDo$do, and we could do without the Do$do.
Yes, that just doesn't fly, does it? withSocketsDo in user code became superfluous a couple of releases back. --sigbjorn

On 11 August 2004 18:24, Sigbjorn Finne wrote:
"Jon Fairbairn"
writes: [1] What's the "Do" doing there anyway? You end up writing withSocketsDo$do, and we could do without the Do$do.
Yes, that just doesn't fly, does it? withSocketsDo in user code became superfluous a couple of releases back.
Interesting. Why is it superfluous? Should it be made a no-op? Shouldn't we at least document that it isn't required any more? Cheers, Simon
participants (5)
-
Bayley, Alistair
-
Glynn Clements
-
Jon Fairbairn
-
Sigbjorn Finne
-
Simon Marlow