<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<META NAME="Generator" CONTENT="MS Exchange Server version 5.5.2657.73">
<TITLE>Distinguishing TCP connections</TITLE>
</HEAD>
<BODY>

<P><FONT SIZE=2>Eric,</FONT>
</P>

<P><FONT SIZE=2>I came up with a nice way of managing connections on the last project I worked on:</FONT>
</P>

<P><FONT SIZE=2>The DataConnection is the protocol instance (in this case inheriting from Int32StringReceiver).&nbsp; Each time a protocol connects it calls the registerSource</FONT></P>

<P><FONT SIZE=2>class DataConnection(Int32StringReceiver):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp; </FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp; def __init__(self, manager):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.manager = manager</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp; </FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp; def closeConnection(self):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.transport.loseConnection()</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp; </FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp; def connectionMade(self):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print 'registering connection'</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.registerConnection()</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp; def connectionLost(self, reason):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print 'connection lost, removing....'</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.removeConnection()</FONT>
</P>

<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT SIZE=2>.</FONT>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT SIZE=2>.</FONT>
<BR><FONT SIZE=2>[ code omitted for brevity ]</FONT>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT SIZE=2>.</FONT>
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT SIZE=2>.</FONT>
<BR><FONT SIZE=2>&nbsp;</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp; def registerConnection(self):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; register data connection with connection manager.</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.manager.registerSource(self)</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp; def removeConnection(self):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; remove this connection from the connection manager.</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.manager.removeSource(self.id)</FONT>
</P>

<P><FONT SIZE=2>&nbsp;&nbsp;&nbsp; def setId(self, id):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.id = id</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT>
<BR><FONT SIZE=2>And the ConnectionManager is the factory class (inherited from the generic Factory class).</FONT>
<BR><FONT SIZE=2>&nbsp;</FONT>
<BR><FONT SIZE=2>class ConnectionManager(Factory):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp; </FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp; def __init__(self, eventhandler):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.ids = 0</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.sources = {}</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.eventhandler = eventhandler&nbsp;&nbsp;&nbsp; # -- see comments later</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp; </FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp; def buildProtocol(self, addr):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return DataConnection(self)</FONT>
</P>

<P><FONT SIZE=2>&nbsp;&nbsp;&nbsp; def newId(self):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get an id that is unique for the life of the connection manager.</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; id = self.ids+1</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.ids = id</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return id</FONT>
</P>

<P><FONT SIZE=2>&nbsp;&nbsp;&nbsp; def registerSource(self, source):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; register a new source, this assigns the source an id and</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; adds it to the sources dictionary.</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; id = self.newId()</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.sources[id] = source</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # set source id</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; source.setId(id)</FONT>
</P>

<P><FONT SIZE=2>&nbsp;&nbsp;&nbsp; def removeSource(self, id):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; remove the connection indicated by the source id from the current connection</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pool any subsequent behaviour must be handled in the event manager.</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.sources.has_key(id):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; del self.sources[id]</FONT>
</P>

<P><FONT SIZE=2>&nbsp;&nbsp;&nbsp; def closeConnections(self):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for source in self.sources.values():</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; source.closeConnection()</FONT>
</P>

<P><FONT SIZE=2>[ code omitted for brevity ]</FONT>
</P>

<P><FONT SIZE=2>As you can see the when a connection is made it is registered with the factory instance.&nbsp; This uniquely identifies the connection, and allows you to identify when you get a message which connection it is from.&nbsp; This also simplifies sending a message back along the same channel:</FONT></P>

<P><FONT SIZE=2>To do this you can create an event handler that implements some form of event processing:</FONT>
</P>

<P><FONT SIZE=2>class EventHandler:</FONT>
</P>

<P><FONT SIZE=2>&nbsp;&nbsp;&nbsp; def __init__(self, manager):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.manager = manager</FONT>
</P>

<P><FONT SIZE=2>&nbsp;&nbsp;&nbsp; def messageReceived(self, id, message):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # process message</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # create new message</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newMessage = &quot;this is a test&quot;</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # send new message back along same connection</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.manager.sendMessage(id, newMessage)</FONT>
</P>

<P><FONT SIZE=2>And in the ConnectionManager add something like the following methods:</FONT>
</P>

<P><FONT SIZE=2>&nbsp;&nbsp;&nbsp; def propagateMessage(self, id, message):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This method simply passes the received message through to the</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EventHandler class instance along with the id of the connection</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; the message was received from.</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.eventhandler.messageReceived(id, message)</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp; def sendMessage(self, id, message):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This method retrieves the correct connection and sends a message through it.</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.sources.has_key(id):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.sources[id].emitMessage(message)</FONT>
</P>

<P><FONT SIZE=2>And the DataConnection:</FONT>
</P>

<P><FONT SIZE=2>&nbsp;&nbsp;&nbsp; def stringReceived(self, data):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.manager.propagateEvent(self.id, data)</FONT>
</P>

<P><FONT SIZE=2>&nbsp;&nbsp;&nbsp; def emitMessage(self, message):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; send a message along the data connection.</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.sendString(message)</FONT>
</P>
<BR>

<P><FONT SIZE=2>If any of this is unclear please let me know.</FONT>
</P>

<P><FONT SIZE=2>Regards,</FONT>
</P>

<P><FONT SIZE=2>Grant McDonald</FONT>
</P>

<P><FONT SIZE=2>----Original Message-----</FONT>
<BR><FONT SIZE=2>From: twisted-python-bounces@twistedmatrix.com [<A HREF="mailto:twisted-python-bounces@twistedmatrix.com">mailto:twisted-python-bounces@twistedmatrix.com</A>]On Behalf Of Eric Hsu</FONT>
<BR><FONT SIZE=2>Sent: 21 June 2005 17:33</FONT>
<BR><FONT SIZE=2>To: radix@twistedmatrix.com</FONT>
<BR><FONT SIZE=2>Cc: Twisted general discussion</FONT>
<BR><FONT SIZE=2>Subject: Re: [Twisted-Python] How could I distinguish each TCP connection?</FONT>
</P>

<P><FONT SIZE=2>Thank you very much!</FONT>
<BR><FONT SIZE=2>You've been a GREAT help :D</FONT>
<BR><FONT SIZE=2>2005/6/21, Christopher Armstrong &lt;radeex@gmail.com&gt;:</FONT>
<BR><FONT SIZE=2>I suggest, instead of using the stock &quot;Factory&quot;, making a subclass of</FONT>
<BR><FONT SIZE=2>it with buildProtocol implemented like so:</FONT>
</P>

<P><FONT SIZE=2>def buildProtocol(self, addr):</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp; p = Factory.buildProtocol(self, addr)</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp; self.connections.append (p)</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp; return p</FONT>
</P>

<P><FONT SIZE=2>Or similar (you'll have to define the 'connections' list yourself in</FONT>
<BR><FONT SIZE=2>__init__). In the protocol's connectionLost, you could then remove the</FONT>
<BR><FONT SIZE=2>protocol from that list.</FONT>
</P>

</BODY>
<!--[object_id=#infocomp.com#]--><P><FONT face=Arial color=#808080 size=1>Important notice: This message is intended for the individual(s) and entity(s) addressed. The information contained in this transmission and any attached, may be confidential and may also be the subject of legal privilege, public interest immunity or legal professional privilege. Any review, retransmission, dissemination or other use of, taking of any action in reliance upon this information by person or entities other than the recipient is prohibited and requires authorization from the sender. If you are not the addressee indicated in this message (or responsible for delivery of the message to such person) you may not copy or deliver this message to anyone. In such cases you should destroy this message and kindly notify the sender by reply email. </FONT></P>
<P><FONT face=Arial color=#808080 size=1>WARNING: Although Infocomp has taken reasonable precautions so that no viruses&nbsp;are present in this e-mail, the company cannot accept responsibility for any loss or damage arising from the use of e-mail attachments.</FONT></P></HTML>