RE: Are handles closed automatically when they fall out of scope?

On 25 October 2004 14:24, John Goerzen wrote:
On 2004-10-25, Simon Marlow
wrote: On 22 October 2004 21:58, Peter Simons wrote:
On 24 October 2004 23:37, John Goerzen wrote:
* What happens when one Handle corresponding to a socket is closed, but another isn't?
You shouldn't have two Handles on the same socket. This is an unchecked error.
This does seem useful, though. I am actually doing this in my code and it works. One Handle is opened ReadOnly, the other WriteOnly. That way, I can use hGetContents on the reading side in my network code.
If I tried that with a single Handle opened ReadWrite, then I'd get errors about it being closed whenever I'd try to write out some data.
I wasn't able to find any other good way around it.
Hmmm, you should still be able to *write* to a socket handle that has had hGetContents applied to it. In GHC, a ReadWrite handle to a socket basically consists of a wrapper around two independent Handles, one for read and one for write, each with its own buffer. ... I just tested it with 6.2.2, and indeed it does work as I expected. But perhaps there's a bug lurking somewhere? If you do socketToHandle twice, then the danger is that one of the Handles will be finalized and close the FD before the other Handle has finished with it. In 6.4 you'll be able to use hDuplicate for this, BTW. Cheers, Simon

On 2004-10-25, Simon Marlow
If I tried that with a single Handle opened ReadWrite, then I'd get errors about it being closed whenever I'd try to write out some data.
I wasn't able to find any other good way around it.
Hmmm, you should still be able to *write* to a socket handle that has had hGetContents applied to it. In GHC, a ReadWrite handle to a socket basically consists of a wrapper around two independent Handles, one for read and one for write, each with its own buffer.
You were right. Long story, but I had a different bug that happened to get fixed at the same time. Which brings up another question: The problem was that I was trying to *read* using hGetContents more than once. I have this data structure: data FTPConnection = FTPConnection {readh :: IO String, writeh :: Handle, socket_internal :: Socket, isPassive :: Bool} Now, if I set readh to to be hGetContents h, then the first read I try to make using it works, but subsequent ones don't, since the first one made it half-closed already. If I make readh a plain string, instead of an IO String, then each time I try to read from it, I start back at the very beginning -- reading the same response from the network over and over, in other words. In this case, my workaround was to write my own simple version of hGetContents that uses hGetChar and doesn't make anything half-closed. Maybe there's a better way?
If you do socketToHandle twice, then the danger is that one of the Handles will be finalized and close the FD before the other Handle has finished with it.
In this particular case, my data structure is opaque, so nobody else will be able to access the underlying handles. But thanks for the caution -- I will be sure to remember that. -- John

John Goerzen writes:
Now, if [I read with hGetContents h], then the first read I try to make using it works, but subsequent ones don't, since the first one made it half-closed already.
Maybe I misunderstood something ... but why do you need to read from the stream multiple times after calling hGetContents? The function returns the _entire_ (lazily evaluated) input stream, there is no need to read again. You already _have_ everything. Peter

On 2004-10-25, Peter Simons
John Goerzen writes:
Now, if [I read with hGetContents h], then the first read I try to make using it works, but subsequent ones don't, since the first one made it half-closed already.
Maybe I misunderstood something ... but why do you need to read from the stream multiple times after calling hGetContents? The function returns the _entire_ (lazily evaluated) input stream, there is no need to read again. You already _have_ everything.
Because I'd have to use a state monad or something to chop off the top of the list each time I read from it. This is a FTP client module, so, for instance, you might see this session: cwd h "/pub/linuc" nlst h Nothing etc. Each command sends something and reads a reply. "h" holds an instance of that data structure I posted. If I just try to read from the list during each command, I would just read the same (first) response over and over again. Or, I'd have to store a position (which also requires a state monad), which would lead to wasting memory keeping all that stuff around.

On Mon, Oct 25, 2004 at 09:42:13PM +0000, John Goerzen wrote:
Maybe I misunderstood something ... but why do you need to read from the stream multiple times after calling hGetContents? The function returns the _entire_ (lazily evaluated) input stream, there is no need to read again. You already _have_ everything.
Because I'd have to use a state monad or something to chop off the top of the list each time I read from it. This is a FTP client module, so, for instance, you might see this session:
cwd h "/pub/linuc" nlst h Nothing
etc.
Each command sends something and reads a reply. "h" holds an instance of that data structure I posted.
If I just try to read from the list during each command, I would just read the same (first) response over and over again. Or, I'd have to store a position (which also requires a state monad), which would lead to wasting memory keeping all that stuff around.
Sounds to me like you really want to be putting the code doing this inside of the IO monad. It is interacting with the outside world, and maintaining state at that... Dave
participants (4)
-
David Brown
-
John Goerzen
-
Peter Simons
-
Simon Marlow