简体   繁体   中英

Twisted Python - Push data to websocket

I've a web-socket server which connects with the clients. Following is the code:-

from twisted.internet.protocol import Factory
from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor

class Chat(LineReceiver):

    def __init__(self, users):
        self.users = users
        self.name = None
        self.state = "GETNAME"

    def connectionMade(self):
        self.sendLine("What's your name?")

    def connectionLost(self, reason):
        if self.users.has_key(self.name):
            del self.users[self.name]

    def lineReceived(self, line):
        if self.state == "GETNAME":
            self.handle_GETNAME(line)
        else:
            self.handle_CHAT(line)

    def handle_GETNAME(self, name):
        if self.users.has_key(name):
            self.sendLine("Name taken, please choose another.")
            return
        self.sendLine("Welcome, %s!" % (name,))
        self.name = name
        self.users[name] = self
        self.state = "CHAT"

    def handle_CHAT(self, message):
        # Need to send the message to the connected clients.


class ChatFactory(Factory):

    def __init__(self):
        self.users = {} # maps user names to Chat instances

    def buildProtocol(self, addr):
        return Chat(self.users)


reactor.listenTCP(8123, ChatFactory())
reactor.run()

Clients get connected to the above code(server), and sends the data to the server.

Now, I've another python script, basically a scraper which scrapes the web, processes it and finally need to send the data to the connected clients.

script.py

while True:
    # call `send_message` function and send data to the connected clients.

How can I achieve it?? Any example would be of great help!!

UPDATE

After using Autobahn

I've a server that fetches data from 3rd party API. I want to send this data to all the connected web-socket clients. Here is my code:-

class MyServerProtocol(WebSocketServerProtocol):
    def __init__(self):
        self.connected_users = []
        self.send_data()

    def onConnect(self, request):
        print("Client connecting: {0}".format(request.peer))
        
    def onOpen(self):
        print("WebSocket connection open.")
        self.connected_users.append(self)  # adding users to the connected_list

    def send_data(self):
        # fetch data from the API and forward it to the connected_users.
        for u in self.users:
            print 1111
            u.sendMessage('Hello, Some Data from API!', False)

    def onClose(self, wasClean, code, reason):
        connected_users.remove(self)  # remove user from the connected list of users
        print("WebSocket connection closed: {0}".format(reason))


if __name__ == '__main__':

    import sys

    from twisted.python import log
    from twisted.internet import reactor

    factory = WebSocketServerFactory(u"ws://127.0.0.1:9000")
    factory.protocol = MyServerProtocol    

    reactor.listenTCP(9000, factory)
    reactor.run()

My Server will never receive a message or probably will receive, but as of right now there's no such use-case, hence no need for OnMessage event for this example).

How do I write my send_data function in order to send data to all my connected clients??

You need to avoid this pattern when writing software with Twisted:

while True:
    # call `send_message` function and send data to the connected clients.

Twisted is a cooperative multitasking system. "Cooperative" means that you have to give up control of execution periodically so that other tasks get a chance to run.

twisted.internet.task.LoopingCall can be used to replace many while ... loops (particularly while True loops):

from twisted.internet.task import LoopingCall
LoopingCall(one_iteration).start(iteration_interval)

This will call one_iteration every iteration_interval seconds. In between, it will give up control of execution so other tasks can run.

Making one_iteration send a message to a client is just a matter of giving one_iteration a reference to that client (or those clients, if there are many).

This is a variation on the FAQ How do I make Input on One Connection Result in Output on Another .

If you have a ChatFactory with a dict containing all your clients, just pass that factory to one_iteration :

LoopingCall(one_iteration, that_factory)

or

LoopingCall(lambda: one_iteration(that_factory))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM