prattom
prattom

Reputation: 1743

sending data to particular client from twisted server

I have written server part using twisted python. Now 4 clients are connected to server which send some data to server. If client 1 sends some data to server then server forwards that data to client 4 and similarly when client 2 sends data to server then server forwards that data to client 3. Thus my problem is that how can I choose particular client on basis of ip address to which I have to send data. In the twisted examples that I have seen to send data to client following code is used

self.transport.write("string")

How can I specify ip address of client to which I have to send data?

My server in tcp server and clients are also tcp(python twisted)

Upvotes: 3

Views: 2137

Answers (1)

Jean-Paul Calderone
Jean-Paul Calderone

Reputation: 48315

self.transport.write("string")

In the examples you refer to, self is an instance of Protocol or a subclass of Protocol (or an object that provides IProtocol without subclassing Protocol, which is also completely fine).

self.transport is therefore an object that provides ITransport (perhaps it provides the more specific ITCPTransport or ISSLTransport but that's not important in the context of this question).

In Twisted, an object that provides ITransport represents a connection between two endpoints. Such a connection might be an IPv4/TCP connection or an IPv6/TLS connection or an AF_UNIX connection. What all of these kinds of connections have in common is that they have exactly two endpoints. Data can be "sent" from one endpoint and "received" at the other endpoint (and vice versa).

The reason self.transport.write("string") doesn't obviously include any addressing information is that self.transport already includes that information.

Since self.transport represents a connection (and only one connection: no more, no less) and every connection has two endpoints, the addresses of those two endpoints are necessarily part of self.transport (were they not, self.transport could not represent that connection).

And the object is actually slightly more specific than this: it represents one side of the connection. It knows which of the two endpoints is "here" and which is somewhere else. This means that when you write data to self.transport there is only one possible address to which it can be sent: the endpoint of the connection represented by self.transport which is not "here".

By convention, that endpoint has a name. It is the "peer". The interface ITransport defines a method, getPeer, which exposes to you the "peer" address of the connection the transport object represents. self.transport.getPeer() returns an object that represents that address. The exact shape of that object depends on what kind of connection you have.

You asked how can I choose particular client on basis of ip address. If it is really the case that data flowing through your system has its destination explicitly specified by an IP address then you can use getPeer to find a connection that matches the required address.

However, it is much more common to stop using the connection's endpoint's addresses after you've set up the connection. IP address information tends to be unreliable because of the degree to which NAT has been deployed. It is not always wrong to embed IP addresses in your application-level protocol but it is hard to think of examples where it is right.

Fortunately, the alternative is even easier. self.transport already represents a certain connection. This is just a regular old Python object. Once you know which two clients are meant to be exchanging data with each other you only need to use the objects to get data sent to the right place.

For example, if you have a server that accepts exactly four connections and a factory which saves a reference to the IProtocol provider it creates to handle each of those connections (think about that for a minute: since each ITransport provider represents exactly one connection, what must it mean about protocol objects that have a transport attribute that refers to one of those? If two protocol objects referred to the same transport... And a single protocol object's transport attribute can't possible refer to more than one object...) as attributes one, two, three, four then when one of those protocol objects implemented its dataReceived method like this:

def dataReceived(self, bytes):
    message = self._parseNewData(bytes)
    if message.complete():
        self.factory.four.transport.write(message.tostring())

This must necessarily be writing data to the fourth connection established to the server. There is no explicit addressing in this example. There is just careful use of certain Python objects.

Careful use of certain Python objects is the overall answer to this question.

Upvotes: 5

Related Questions