Sanic: Can I just call send in sanic's websocket without calling recv?

Created on 19 Apr 2019  路  3Comments  路  Source: sanic-org/sanic

I am using the sanic websocket example to use websocket. I just want to send data to the browser, but the example calls the recv function. How should I remove the recv and continue to send data to the browser?

  1. After removing recv, the browser can't receive data, and there is no way to transfer data later.

  2. Keep recv, the first time the data browser is not received, of course, the next time will not be sent.

  3. Keep recv, the browser will reply to any data after receiving the first sent data, and then I can send the following data.

In these cases, sanic will return to 403. And did not give any tips.

This is my code:

from sanic import Sanic, response
from sanic_cors import CORS
from sanic.websocket import WebSocketProtocol
import time

@api.websocket('/devices/values')
async def feed(request, ws):
    while True:
        logger.debug("sending data.")
        await ws.send(json.dumps(data))
        recv_data = await ws.recv()
        logger.debug("recv data [%s].", recv_data)
        time.sleep(10)

According to the principle of websocket I just checked, this should not happen, so can someone give me some advice?
Thanks!

Most helpful comment

Thank you very much for your reply! @chenjr0719 @ahopkins
I am sorry to reply so long.
I have tested and replaced time.sleep(10)with asyncio.sleep(10) without waiting for data to be received.
I don't need to accept any data, so this is enough.
And then I used zeroMQ to update the data. The websocket just sends data to the page.
So this is over, thank you!

All 3 comments

You definitely do not have to have bi-directional communication. You can implement just push events by not calling receive. I'm writing from my phone, but I'll post a snippet when I am back online.

@FishEatingCat

If you only want to send data, you can try this:

import asyncio

import ujson

from sanic import Sanic
from sanic.log import logger


app = Sanic()

@app.websocket('/ws')
async def feed(request, ws):
    while True:
        logger.debug("sending data.")
        data = {'foo': 'bar'}
        await ws.send(ujson.dumps(data))
        await asyncio.sleep(10)


if __name__ == "__main__":
    app.run()

But just like you said

  1. After removing recv, the browser can't receive data, and there is no way to transfer data later.
  2. Keep recv, the first time the data browser is not received, of course, the next time will not be sent.
  3. Keep recv, the browser will reply to any data after receiving the first sent data, and then I can send the following data.

Because await ws.recv() will keep waiting until there is incoming data.
So, let's do a little trick here:

import asyncio

import async_timeout
import ujson

from sanic import Sanic
from sanic.log import logger

app = Sanic()

@app.websocket('/ws')
async def feed(request, ws):
    data = {'foo': 'bar'}
    while True:
        try:
            with async_timeout.timeout(5):
                data = await ws.recv()
                logger.debug("recv data {}.".format(data))
        except:
            pass

        logger.debug("sending data {}.".format(data))
        await ws.send(ujson.dumps(data))


if __name__ == "__main__":
    app.run(debug=True)

The log will be:

[2019-04-30 13:45:04 +0800] [1876] [DEBUG] 

                 Sanic
         Build Fast. Run Fast.


[2019-04-30 13:45:04 +0800] [1876] [INFO] Goin' Fast @ http://127.0.0.1:8000
[2019-04-30 13:45:04 +0800] [1880] [INFO] Starting worker [1880]
[2019-04-30 13:45:14 +0800] [1880] [DEBUG] sending data {'foo': 'bar'}.
[2019-04-30 13:45:19 +0800] [1880] [DEBUG] sending data {'foo': 'bar'}.
[2019-04-30 13:45:24 +0800] [1880] [DEBUG] sending data {'foo': 'bar'}.
[2019-04-30 13:45:29 +0800] [1880] [DEBUG] sending data {'foo': 'bar'}.
[2019-04-30 13:45:31 +0800] [1880] [DEBUG] recv data {"new": "message"}.
[2019-04-30 13:45:31 +0800] [1880] [DEBUG] sending data {"new": "message"}.
[2019-04-30 13:45:36 +0800] [1880] [DEBUG] sending data {"new": "message"}.
[2019-04-30 13:45:41 +0800] [1880] [DEBUG] sending data {"new": "message"}.
[2019-04-30 13:45:46 +0800] [1880] [DEBUG] sending data {"new": "message"}.

This implement can always send data even there is no incoming data but also capable to receive data if you need it.
Can this solve your problem?

Thank you very much for your reply! @chenjr0719 @ahopkins
I am sorry to reply so long.
I have tested and replaced time.sleep(10)with asyncio.sleep(10) without waiting for data to be received.
I don't need to accept any data, so this is enough.
And then I used zeroMQ to update the data. The websocket just sends data to the page.
So this is over, thank you!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ubergarm picture ubergarm  路  4Comments

Souldat picture Souldat  路  3Comments

graingert picture graingert  路  3Comments

olalonde picture olalonde  路  3Comments

geekpy picture geekpy  路  4Comments