[Kamaelia] TCPClient: How to sense connection failure?

Michael Sparks ms at cerenity.org
Sun Jan 13 00:11:23 CET 2008


Bjoern Schliessmann wrote:
> Hello,
> 
> I'm currently trying to implement a simulation program with Kamaelia
> and need a reliable TCP connection to a data server.

The behaviour you're seeing sounds odd (which is hopefully encouraging :-),
but it's not clear from the description whether its a bug in your code or
Kamaelia. One question I really have as a result is what version are you
using?

Current release version 0.5.0, the version on /trunk, or the bleeding edge
version on /branches/private_MPS_Scratch. (I'm using the latter to run my
greylisting server - as are a few others).

All that said though, looking at the differences between versions, I'm not
convinced they're large enough to show the problem you're seeing.

I'm not about to rule out a bug I don't know about though :-)

> From Twisted, I know that a method is called if the connection fails
> by whatever reason. I tried to get the same results with Kamaelia's
> TCPClient component. If I start up the component and try to connect
> to a closed TCP port it fails and sends a message out of the signal
> box, that's okay.

If you'd prefer more information in that message, please let me know.
(all components send out a message when they shutdown. For things that
send  data out as one of their primary actions send out a producerFinished
message)

> But if the connection attempt succeeds and, after some time, the
> server drops the connection with full TCP handshake (FIN, FIN+ACK,
> ACK), the component just hangs and does nothing. Is this by design,
> or could there be an error in my setup?

It sounds like an error in your setup... but I hate saying that. (Doesn't
tell me or you what it is, and doesn't help change things to discourage or
detect mistakes in usage)

When the server drops the connection in my setups, the client disconnects
cleanly when the server dies, with the client code looking like this:
      self.send(producerFinished(self,self.howDied), "signal")

Meaning you get a message telling you how the component shutdown as well as
the fact it shutdown. (If "howDied" is None, it's just a normal shutdown -
ie as a result of being told to shut down)

The function where this is managed is runClient in the class 
   Kamaelia.Internet.TCPClient.TCPClient
(fully qualified name)

The actual socket connections are handled by a class called
ConnectedSocketAdapter which manages all logic of checking for
errors, remote shutdown etc. That works the same for both servers
and clients so breakage in clients would show up as breakage in servers
as well, which would be particularly bad. 

> Also, how long does a TCPClient component live -- or how can/should
> I terminate it explicitly? I'm afraid that if I create
> a "ReconnectingTCPClient" component, it could eat up memory over
> long runtime with hanging TCPClients.

That shouldn't be an issue (I hate the word "should"), but you can do this
using a carousel component. (I ought to write that as an example of how to
use the Carousel component)

In the meantime - whilst I check to see if there's a bug I didn't know
about, the following 2 cookbook entries may be of use:
   * http://kamaelia.sourceforge.net/Cookbook/TCPSystems
   * http://kamaelia.sourceforge.net/Cookbook/Carousels - allows you to make
     something that exits reusable. It's a little awkward to get your head
     around, but is quite useful when you do. (I've heard of others using
     Carousel & TCPClient to make a reconnecting TCPClient in the past)

All that said, I'm not going to rule out a bug and look into it. (if you
have a simple example you find fails, please forward it to me :)

*thinks*

The following code may also be useful when debugging:

from Kamaelia.Chassis.Pipeline import Pipeline

class PeriodicWakeup(Axon.ThreadedComponent.threadedcomponent):
    interval = 300
    def main(self):
        while 1:
            time.sleep(self.interval)
            self.send("tick", "outbox")

class WakeableIntrospector(Axon.Component.component):
    def main(self):
        while 1:
            Q = [ q.name for q in self.scheduler.listAllThreads() ]
            Q.sort()
            print "*debug* THREADS"+ str(Q)
            self.scheduler.debuggingon = False
            yield 1
            while not self.dataReady("inbox"):
                self.pause()
                yield 1
            while self.dataReady("inbox"):
                self.recv("inbox")

Pipeline(
    PeriodicWakeup(),
    WakeableIntrospector(),
).activate()

If you put this code somewhere before your "run" call, you'll get periodic
output to tell you what's running. When debugging manually I'd drop the
interval to 3-10 seconds or so. I use 300 for a server.

Now, off to see if I can reproduce your problem... :)

Regards,


Michael.
--
http://kamaelia.sourceforge.net/Home
http://yeoldclue.com/blog




More information about the Python-list mailing list