Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/344.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何从异步函数发送websocket.send()数据_Python_Websocket_Rx Py_Sanic - Fatal编程技术网

Python 如何从异步函数发送websocket.send()数据

Python 如何从异步函数发送websocket.send()数据,python,websocket,rx-py,sanic,Python,Websocket,Rx Py,Sanic,我正在学习asyncio,并试图找出如何将数据从一个异步函数传递到另一个异步函数中的websocket循环 在我的场景中,数据由某个第三方发布到web API。我想将POST数据回显到已连接的websocket客户端 Sanic&Rx不是要求,但这是我开始走的路。以下是我到目前为止的想法: #!/usr/bin/env python from sanic import Sanic from sanic import response from sanic.response import fil

我正在学习asyncio,并试图找出如何将数据从一个异步函数传递到另一个异步函数中的websocket循环

在我的场景中,数据由某个第三方发布到web API。我想将POST数据回显到已连接的websocket客户端

Sanic&Rx不是要求,但这是我开始走的路。以下是我到目前为止的想法:

#!/usr/bin/env python

from sanic import Sanic
from sanic import response
from sanic.response import file
from rx import Observable

app = Sanic(__name__)

@app.route('/')
async def index(request):
    return await file('ws.html')

async def observable_message(message):
    return Observable.from_(message)

@app.route('/post', methods=["POST"])
async def message_inbound(request):
    payload = request.json
    await observable_message(payload)
    return response.json({"status": "OK"})

@app.websocket('/feed')
async def feed(request, ws):
    while True:
        message = await app.stream
        print('Sending: ' + message)
        await ws.send(message)

@app.listener('before_server_start')
async def setup_observable_stream(app, loop):
    app.stream = Observable.start_async(observable_message)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=9000, workers=4, debug=True)
这显然是行不通的,因为observable_message()需要消息作为arg,而我正试图使用它来启动_async(),所以我被难住了。我怎样才能把这些东西连接起来

客户端可能很琐碎:

<!DOCTYPE html>
<html>
<head><title>POST data</title></head>
<body>
<script>
    var ws = new WebSocket('ws://' + document.domain + ':' + location.port + '/feed'),
        messages = document.createElement('ul');
    ws.onmessage = function (event) {
        var messages = document.getElementsByTagName('ul')[0],
            message = document.createElement('li'),
            content = document.createTextNode('Received: ' + event.data);
        message.appendChild(content);
        messages.appendChild(message);
    };
    document.body.appendChild(messages);
</script>
</body>
</html>

发布数据
var ws=new WebSocket('ws://'+document.domain+':'+location.port+'/feed'),
messages=document.createElement('ul');
ws.onmessage=函数(事件){
var messages=document.getElementsByTagName('ul')[0],
message=document.createElement('li'),
content=document.createTextNode('Received:'+event.data);
message.appendChild(内容);
messages.appendChild(message);
};
document.body.appendChild(消息);

也许有更好的方法让它与Rx一起工作,但我发现简化有助于推理。这项工作:

#!/usr/bin/env python

import asyncio
import uvloop

from sanic import Sanic
from sanic import response
from sanic.response import file
from sanic.websocket import ConnectionClosed

app = Sanic(__name__)

app.ws_clients = set()
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())

@app.route('/')
async def index(request):
    return await file('ws.html')

@app.route('/post', methods=["POST"])
async def message_inbound(request):
    payload = request.body.decode("utf-8")
    await broadcast(payload)
    return response.json({"status": "OK"})

async def broadcast(message):
    broadcasts = [ws.send(message) for ws in app.ws_clients]
    for result in asyncio.as_completed(broadcasts):
        try:
            await result
        except ConnectionClosed:
            print("ConnectionClosed")
        except Exception as ex:
            template = "An exception of type {0} occurred. Arguments:\n{1!r}"
            message = template.format(type(ex).__name__, ex.args)
            print(message)

@app.websocket("/ws")
async def websocket(request, ws):
    app.ws_clients.add(ws)
    await ws.send("Connected.")
    print(f'{len(app.ws_clients)} clients')
    while True:
        data = await ws.recv()
        print('Received: ' + data)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=9005, workers=1, debug=False)

谢谢,非常有用!只有一个小问题:如果“wait result”引发“ConnectionClosed”,那么从“app.ws\u客户端”中删除ws会更好吗?