Mailing List Archive

Socket programming.
I'm trying to implement a simple irc module as the base for a simple
irc client. However, I'm having some design problems, having never
done any socket programming before.

My current implementation is threaded (using fork()); one thread for
user interaction and one for server output. It uses blocking
sockets. It works ok, but I've read some docs here and there (amongst
them the Socket Programming HOWTO on www.python.org) and I get the
feeling I should be using select() and non-blocking sockets. Also,
I'm not sure I want to use fork() -- it seems very low-level and
depends on a Unix-like system.

Advice would be appreciated. If you think I'm being unclear or vague
-- you're probably right. ;) I'm not really sure what I'm asking,
either.

--
Gravity brings me down.
Socket programming. [ In reply to ]
From: Christopher Petrilli <petrilli@trump.amber.org>

Kjetil =D8degaard <kjetilod@stud.ntnu.no> wrote:
> My current implementation is threaded (using fork()); one thread for
> user interaction and one for server output. It uses blocking
> sockets. It works ok, but I've read some docs here and there (amongst
> them the Socket Programming HOWTO on www.python.org) and I get the
> feeling I should be using select() and non-blocking sockets. Also,
> I'm not sure I want to use fork() -- it seems very low-level and
> depends on a Unix-like system.

First, fork() isn't really threading... if you want to do threading, then
you should use the threading module, if it' ssupported on your platform.

Second, for that kind of thign, take a look at asyncore and asynchat,
the first of which I've written documentation for that will be released
in the next itteration of the Python library reference. asynchat
should be able to do what you want.

Chris
--=20
| Christopher Petrilli ``Television is bubble-gum for
| petrilli@amber.org the mind.''-Frank Lloyd Wrig=
ht
Socket programming. [ In reply to ]
Kjetil =D8degaard <kjetilod@stud.ntnu.no> wrote:
> My current implementation is threaded (using fork()); one thread for
> user interaction and one for server output. It uses blocking
> sockets. It works ok, but I've read some docs here and there (amongst
> them the Socket Programming HOWTO on www.python.org) and I get the
> feeling I should be using select() and non-blocking sockets. Also,
> I'm not sure I want to use fork() -- it seems very low-level and
> depends on a Unix-like system.

First, fork() isn't really threading... if you want to do threading, then
you should use the threading module, if it' ssupported on your platform.

Second, for that kind of thign, take a look at asyncore and asynchat,
the first of which I've written documentation for that will be released
in the next itteration of the Python library reference. asynchat
should be able to do what you want.

Chris
--=20
| Christopher Petrilli ``Television is bubble-gum for
| petrilli@amber.org the mind.''-Frank Lloyd Wrig=
ht
Socket programming. [ In reply to ]
"Kjetil Ødegaard" <kjetilod@stud.ntnu.no> writes:
| I'm trying to implement a simple irc module as the base for a simple
| irc client. However, I'm having some design problems, having never
| done any socket programming before.
|
| My current implementation is threaded (using fork()); one thread for
| user interaction and one for server output. It uses blocking
| sockets. It works ok, but I've read some docs here and there (amongst
| them the Socket Programming HOWTO on www.python.org) and I get the
| feeling I should be using select() and non-blocking sockets. Also,
| I'm not sure I want to use fork() -- it seems very low-level and
| depends on a Unix-like system.

These are questions everyone wrestles with, and the only thing we can
say for sure is ``it depends.'' If your current design works, it sounds
fine to me.

As you know, select comes in when you want to dispatch from two or more
I/O event sources, in a single execution thread. (With select, you really
don't need non-blocking sockets, because select's job is to predict whether
a read would block.) If the event handling can be simplified to the point
where with a modest amount of global state information, the program can
handle any event in no time and get back to the dispatch loop more or less
right away, then it's worth thinking about a single threaded design.

But it can be more complicated than you expect - for example, when you
write to a socket device, write() or send() may return after writing less
than the full amount, and you have to keep sending until everything goes.
So your global state may have to queue outbound data. (Use select to find
out whether write will block, too.) This is the kind of thing you'd need
to consider in a single threaded service, not necessarily in a client.

This kind of worry is avoided with a multi-threaded design, and then
the question is whether to use processes or threads. Processes are
more expensive and indeed a bit less portable. My favorite OS, BeOS,
supports fork - but a child fork doesn't inherit an open socket, so
fork is a very difficult way to make a multi-threaded socket application!
Moreover, select is available for sockets, but the last I checked it
doesn't work on all types of file descriptors. (I present this as
an example of a non-UNIX socket system that I think even its designers
would admit is slightly lame. I expect something better is on the way.)

BeOS enthusiasts aren't troubled by this, they feel that threads are
available to solve all these dispatching problems. But threads carry
their own problems, as there's a lot more potential for collision when
two threads run in the same address space, so you need to sweat interlocks
that aren't an issue in separate forks. (And Python itself has to deal
with this, as a threaded C program, which complicates the issue.)
Meanwhile the larger program sort of loses control over its threads,
compared to the single threaded select dispatching described above,
because threads blocking on I/O can't process other events, they can't
tell you whether they're actually reading or just blocking, etc.

So the old ways are best, is what I say. Unless they aren't, and at
times they aren't.

Donn Cave, University Computing Services, University of Washington
donn@u.washington.edu
Socket programming. [ In reply to ]
From: donn@u.washington.edu (Donn Cave)

"Kjetil Ødegaard" <kjetilod@stud.ntnu.no> writes:
| I'm trying to implement a simple irc module as the base for a simple
| irc client. However, I'm having some design problems, having never
| done any socket programming before.
|
| My current implementation is threaded (using fork()); one thread for
| user interaction and one for server output. It uses blocking
| sockets. It works ok, but I've read some docs here and there (amongst
| them the Socket Programming HOWTO on www.python.org) and I get the
| feeling I should be using select() and non-blocking sockets. Also,
| I'm not sure I want to use fork() -- it seems very low-level and
| depends on a Unix-like system.

These are questions everyone wrestles with, and the only thing we can
say for sure is ``it depends.'' If your current design works, it sounds
fine to me.

As you know, select comes in when you want to dispatch from two or more
I/O event sources, in a single execution thread. (With select, you really
don't need non-blocking sockets, because select's job is to predict whether
a read would block.) If the event handling can be simplified to the point
where with a modest amount of global state information, the program can
handle any event in no time and get back to the dispatch loop more or less
right away, then it's worth thinking about a single threaded design.

But it can be more complicated than you expect - for example, when you
write to a socket device, write() or send() may return after writing less
than the full amount, and you have to keep sending until everything goes.
So your global state may have to queue outbound data. (Use select to find
out whether write will block, too.) This is the kind of thing you'd need
to consider in a single threaded service, not necessarily in a client.

This kind of worry is avoided with a multi-threaded design, and then
the question is whether to use processes or threads. Processes are
more expensive and indeed a bit less portable. My favorite OS, BeOS,
supports fork - but a child fork doesn't inherit an open socket, so
fork is a very difficult way to make a multi-threaded socket application!
Moreover, select is available for sockets, but the last I checked it
doesn't work on all types of file descriptors. (I present this as
an example of a non-UNIX socket system that I think even its designers
would admit is slightly lame. I expect something better is on the way.)

BeOS enthusiasts aren't troubled by this, they feel that threads are
available to solve all these dispatching problems. But threads carry
their own problems, as there's a lot more potential for collision when
two threads run in the same address space, so you need to sweat interlocks
that aren't an issue in separate forks. (And Python itself has to deal
with this, as a threaded C program, which complicates the issue.)
Meanwhile the larger program sort of loses control over its threads,
compared to the single threaded select dispatching described above,
because threads blocking on I/O can't process other events, they can't
tell you whether they're actually reading or just blocking, etc.

So the old ways are best, is what I say. Unless they aren't, and at
times they aren't.

Donn Cave, University Computing Services, University of Washington
donn@u.washington.edu
Socket programming. [ In reply to ]
From: "Kjetil Ødegaard" <kjetilod@stud.ntnu.no>

I'm trying to implement a simple irc module as the base for a simple
irc client. However, I'm having some design problems, having never
done any socket programming before.

My current implementation is threaded (using fork()); one thread for
user interaction and one for server output. It uses blocking
sockets. It works ok, but I've read some docs here and there (amongst
them the Socket Programming HOWTO on www.python.org) and I get the
feeling I should be using select() and non-blocking sockets. Also,
I'm not sure I want to use fork() -- it seems very low-level and
depends on a Unix-like system.

Advice would be appreciated. If you think I'm being unclear or vague
-- you're probably right. ;) I'm not really sure what I'm asking,
either.

--
Gravity brings me down.