[Haskell-cafe] createProcess interferes with sockets?

Evan Laforge qdunkan at gmail.com
Tue Apr 23 07:15:49 CEST 2013


On Mon, Apr 22, 2013 at 7:39 PM, Donn Cave <donn at avvanta.com> wrote:
> quoth Evan Laforge <qdunkan at gmail.com>,
> ...
>> Oh I see, because the subprocess inherits the socket connection.  That
>> makes sense, though it's tricky.  Tricky tricky unix.  Why does fork()
>> have to be so complicated?
>
> Well, it's very elegant really.  It's one of the tools UNIX gives
> you to decompose a task into discrete modules, programs running
> in separate processes - but inheriting file descriptors and other
> common environmental stuff.  And in some respects should feel
> familiar to a Haskell programmer - can't modify parent's environment,
> etc.

But the way I see it, it's a bunch of implicit state, which is not
nicely encapsulated in a single data structure but scattered around
invisibly, which is then implicitly copied by a function that claims
to take no arguments... doesn't seem very haskelly to me :)

> For me, moral in the story should be that buffered I/O is not robust,
> for a socket device or anything like it (UNIX pipe, whatever.)  That
> isn't about UNIX, it's just inevitable.  Maybe your client is really
> going to need the timely EOF anyway, but the immediate problem was
> that the server wrote to the socket and the client couldn't see it.
> Because the client read is buffered.  Not robust.

Actually, my original code turns off buffering on the socket.  I
didn't include it in the example because it didn't have an effect on
the result... but try modifying the server to

        (hdl, _host, _port) <- Network.accept socket
        IO.hSetBuffering hdl IO.NoBuffering

and the client to

    hdl <- Network.connectTo "localhost" port
    IO.hSetBuffering hdl IO.NoBuffering

and it still waits for the subprocess to complete.  Actually, it looks
like it's the client's hGetContents, since hGetChar comes back
immediately.  I guess that's understandable, but even hGetLine blocks.

System.IO doesn't seem to have a hRead :: Int -> IO String, I guess
you have to go down to the POSIX fd level, or read char-by-char.
Though it mysteriously has readIO which doesn't actually do any IO.
And I can't turn on CloseOnExec without closing the handle, converting
to fd, and creating a new handle... but anyway we were talking about
unix, not System.IO infelicities :)

> Some programmers are so wedded to the buffered language platform I/O
> functions that they'll find a way to defeat the buffering or work
> around it.  That can be "nonperformant" where the semantics of the
> read depend on buffering, like getLine;  don't know what would happen
> with hGetContents.  The path that makes sense to me is low level I/O
> (read/recv) that simply returns what's there, up to the specified limit.

The plan9 approach was that you get buffering only if you explicitly
create a buffer and wrap it around the fd.  And there was less
buffering in general, perhaps motivated by the lack of hacks like
isatty().  But I digress...



More information about the Haskell-Cafe mailing list