Python Twisted - How to send the data over the connected socket connections? - python

I've a server as follow:-
class MyServerProtocol(WebSocketServerProtocol):
def onConnect(self, request):
print("Client connecting: {0}".format(request.peer))
def onOpen(self):
print("WebSocket connection open.")
def onMessage(self, payload, isBinary):
self.sendMessage(payload, isBinary)
def onClose(self, wasClean, code, reason):
print("WebSocket connection closed: {0}".format(reason))
The above code receives the message and replies back with the same message. However, my use case is different.
I'm processing some data, storing it into the DB and then finally want to send the data to the connected clients, or one type of data to specific set of connected clients and the other type to another.
How can I do it? How can I call sendMessage function outside the class?

You need to subclass WebSocketServerFactory to keep track of your connections.
Take a look at this example, which stores all the open connections in a list and broadcasts to all of them. You could easily adapt it to send specific messages to certain clients.

Are you sure you don't want to just use WAMP instead of raw WebSockets?
This might be a lot easier for your use-case, as "broadcast information to interested clients" is exactly what the Publish/Subscribe pattern is for.

Related

Python twisted dataReceived method receive complete data at once

This is my code
`
class TestProtocol(Protocol):
def connectionMade(self):
print 'Got connection from', self.transport.client
def dataReceived(self, data):
print(data)
class Test(Factory, HoneypotService):
NAME = 'test'
protocol = TestProtocol
def __init__(self, config=None, logger=None):
HoneypotService.__init__(self, config=config, logger=logger)
self.port = 8888
def getService(self):
return internet.TCPServer(self.port, self)
When I use the telnet 127.0.0.1 8888 command to connect to this service, and input abcdef,Method dataReceived is executed twice,execute result is as follows:
output picture:
enter image description here
Is there any way to execute dataReceived only once, And the output information is abcdef.
I am searching for a long time on net. But no use. Please help or try to give some ideas how to achieve this. 
The output information is abcdef.
As explained in the Twisted FAQ:
TCP is a stream-oriented transport. This means that when you call transport.write, the data may be broken up into arbitrarily-sized chunks for transmission over the network. There is no way for Twisted to determine how large the data originally written to the transport was.
If you want to send a message and receive it whole on the other end of a connection, you must decide on a format for the message and parse it. For example, prefixing the message with a length or terminating it with a message boundary.
https://github.com/twisted/trac-wiki-archive/blob/trunk/FrequentlyAskedQuestions.mediawiki#why-is-protocoldatareceived-called-with-only-part-of-the-data-i-called-transportwrite-with

python3.5: asyncio, How to wait for "transport.write(data)" to finish or to return an error?

I'm writing a tcp client in python3.5 using asyncio
After reading How to detect write failure in asyncio? that talk about the high-level streaming api, I've tried to implement using the low level protocol api.
class _ClientProtocol(asyncio.Protocol):
def connection_made(self, transport):
self.transport = transport
class Client:
def __init__(self, loop=None):
self.protocol = _ClientProtocol()
if loop is None:
loop = asyncio.get_event_loop()
self.loop = loop
loop.run_until_complete(self._connect())
async def _connect(self):
await self.loop.create_connection(
lambda: self.protocol,
'127.0.0.1',
8080,
)
# based on https://vorpus.org/blog/some-thoughts-on-asynchronous-api-design-in-a-post-asyncawait-world/#bug-3-closing-time
self.protocol.transport.set_write_buffer_limits(0)
def write(self, data):
self.protocol.transport.write(data)
def wait_all_data_have_been_written_or_throw():
pass
client = Client()
client.write(b"some bytes")
client.wait_all_data_have_been_written_or_throw()
As per the python documentation, I know write is non-blocking, and I would like the wait_all_data_have_been_written_or_throw to tell me if all data have been written or if something bad happened in the middle (like a connection lost, but I assume there's way more things that can go bad, and that the underlying socket already return exception about it?)
Does the standard library provide a way to do so ?
The question is mainly related to TCP sockets functionality, not asyncio implementation itself.
Let's look on the following code:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.send(b'data')
Successful send() call means the data was transferred into kernel space buffer for the socket, nothing more.
Data was not sent via wire, not received by peer and, obviously, not processed by received.
Actual sending is performed asynchronously by Operation System Kernel, user code has no control over it.
What's why wait_all_data_have_been_written_or_throw() make not much sense: writing without an error doesn't assume receiving these data by peer but only successful moving from user-space buffer to kernel-space one.

Python Twisted best way to signal events to a proxy

I will be hosting a service that will be acting somewhat like a proxy for something I am a client to.
So I want my ProxyService (a twisted.protocol server) to takes lots of actors (clients). On the server side of things, I need a global connection (only need 1 connection to it for all clients) to an ExistingService (code I didn't write, and I'm a client to it).
When the ExistingService says something interesting, I need to broadcast it to all actors.
When an actor says something to my ProxyService, I need to check if it looks good to me. If it does, I need to inform the ExistingService.
I think I know how to solve this using global variables, but just wondering if better way to push the messages.
You have the basic design well established.
It's a basic "man in the middle" approach.
There are many ways to implement it, but this should get you started:
from twisted.internet import endpoints, protocol, reactor
class ProxyClient(protocol.Protocol):
def connectionMade(self):
print('[x] proxy connection made to server')
self.factory.proxy_proto = self
def connectionLost(self, reason):
print('[ ] proxy connection to server lost: {0}'.format(reason))
self.factory.proxy_proto = None
def dataReceived(self, data):
print('==> received {0} from server'.format(data))
print('<== transmitting data to all actors')
for actor in self.factory.actors:
actor.transport.write(data)
class Actor(protocol.Protocol):
def connectionMade(self):
print('[x] actor connection established')
self.factory.actors.add(self)
def connectionLost(self, reason):
print('[ ] actor disconnected: {0}'.format(reason))
self.factory.actors.remove(self)
def dataReceived(self, data):
print('==> received {0} from actor'.format(data))
proxy_connection = self.factory.proxy_factory.proxy_proto
if proxy_connection is not None:
print('<== transmitting data to server through the proxy')
proxy_connection.transport.write(data)
else:
print('[ ] proxy connection to server has not been established')
def setup_servers():
PROXY_HOST = '127.0.0.1'
PROXY_PORT = 9000
proxy_factory = protocol.ClientFactory()
proxy_factory.protocol = ProxyClient
proxy_factory.proxy_proto = None
proxy_factory.actors = set()
proxy_client = endpoints.TCP4ClientEndpoint(reactor, port=PROXY_PORT, host=PROXY_HOST)
proxy_client.connect(proxy_factory)
ACTOR_HOST = '127.0.0.1'
ACTOR_PORT = 8000
actor_factory = protocol.Factory()
actor_factory.protocol = Actor
actor_factory.proxy_factory = proxy_factory
actor_factory.actors = proxy_factory.actors
actor_server = endpoints.TCP4ServerEndpoint(reactor, port=ACTOR_PORT, interface=ACTOR_HOST)
actor_server.listen(actor_factory)
def main():
setup_servers()
reactor.run()
main()
The core logic that allows the data received from the server to be proxied to actors is proxy_factory.actors = set() and actor_factory.actors = proxy_factory.actors.
Most "list-like" containers, for lack of better words, are "global" and this example gives context into each connection's factory objects.
When an actor connects to the server, an Actor protocol is appended to the set and when data is received, each protocol in the set will get the data.
See the respective dataReceived() methods of each protocol object on how that works.
The example above doesn't use global variables at all, but that's not to say that you couldn't use them.
See how far you can get using this method of passing around variables that give context into other objects.
Also, certain situations weren't explicitly handled, such as caching received data in the event the server or actors haven't connected yet.
Hopefully there's enough information here for you to determine the best course of action based on your needs.
There's some room for streamlining the syntax to make it shorter as well.
As a side note. An alternative to global variables is picobox. It's a dependency injector library but I've found that it satisfies most my needs when I require parameters from external sources.

Send commands to twisted server

I have a simple twisted TCP server that I am using to send and receive data from another application. I am able to communicate and send messages to this application once a connection has been established.
What I want to be able to do have an external module command when and what to send to the 3rd party application (instead of when connected). For example, here is my server code:
from twisted.internet import reactor, protocol
# Twisted
class Tcp(protocol.Protocol):
def dataReceived(self, data):
self.transport.write(data)
print 'data received: ', data
# do something with data
def connectionMade(self, msg):
# Want to only transport message when I command not immediately when connected
self.transport.write(msg)
class TcpFactory(protocol.Factory):
def buildProtocol(self, addr):
return Tcp()
reactor.listenTCP(8001, TcpFactory())
reactor.run()
I have another module (operated by a GUI interface) which defines what message to send and this message needs to be passed as 'msg' into connectionMade
What is the best way to do this?
Your 3rd party call will happen from within connectionMade and should not call it directly. The connectionMade is a Twisted callback and it's there to signal that a client is on the other side. It's up to you to dictate what happens after that. So you can do something like make a series of Deferreds/callbacks which take self.transport (this holds relevant client data). In those series of callbacks, you'll have your logic for
communicating with the 3rd party
validating client
sending a message to the client
This is the gist of it:
def connectionMade(self):
d = Deferred()
d.addCallback(self.thirdPartyComm).addErrBack(self.handleError)
d.addCallback(sendMsg)
d.callback(self.transport)
def thirdPartyComm(self, transport):
# logic for talking to 3rd party goes here
# 3rd party should validate the client then provide a msg
# or raise exception if client is invalid
return msg
def handleError(self, error):
# something went wrong, kill client connection
self.transport.loseConnection()
def sendMsg(self, msg):
self.transport.write(msg)

Multi-client UDP server python

I would like to implement an UDP server with Python.
I want to be able to wait for some clients to connect and chat with others at the same time.
I tried to use an SocketServer implementation
import SocketServer
class MyUDPHandler(SocketServer.BaseRequestHandler):
def handle(self):
data = self.request[0].strip()
socket = self.request[1]
print("{} wrote:".format(self.client_address))
print("data -> ", data)
socket.sendto(data.upper(), self.client_address)
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
server = SocketServer.UDPServer((HOST, PORT), MyUDPHandler)
server.serve_forever()
With this implementation, I can send data from different clients to this server.
To be clear, what I want to do is to go in another function when a client sent UDP data to the server to be able to communicate with him. But at the same time, I still want other clients be able to send UDP data. I guess multithreading will be a solution ?
I'm not sure to be clear...
UDP is connectionless. So you can receive messages from multiple clients with just the single SocketServer that you have, and distinguish clients from each other using client_address. You don't need threads or multiple processes.
Since it's a chat server, outgoing messages are probably always in response to incoming ones, but if you want to be able to send unsolicited messages as well, you should replace serve_forever() with handle_request() and set self.timeout in __init__(). This way you can check whether extra actions need to be performed periodically, e.g. once a minute you could send heartbeats or whatever.

Categories