2

In JS socket.io, there's the third param in the emit function of client:

client.emit("event name",{some:"data"},function myack(value){
})

The myack function is passed to server and called with some returning value:

//server side:
myack("foobar");
...

However, I don't see this feature in Python socket.io: https://python-socketio.readthedocs.io/en/latest/api.html#asyncserver-class

Can ack function be passed to Python socket.io server from clientside JS socket.io? Supposed to be using the same application protocol.

Dee
  • 7,455
  • 6
  • 36
  • 70

2 Answers2

4

Yes you can, have a look at the docs: https://python-socketio.readthedocs.io/en/latest/server.html#event-callbacks

From these docs:

When a client sends an event to the server, it can optionally provide a callback function, to be invoked as a way of acknowledgment that the server has processed the event. While this is entirely managed by the client, the server can provide a list of values that are to be passed on to the callback function, simply by returning them from the handler function:

@sio.event def my_event(sid, data):
    # handle the message
    return "OK", 123

Likewise, the server can request a callback function to be invoked after a client has processed an event. The socketio.Server.emit() method has an optional callback argument that can be set to a callable. If this argument is given, the callable will be invoked after the client has processed the event, and any values returned by the client will be passed as arguments to this function. Using callback functions when broadcasting to multiple clients is not recommended, as the callback function will be invoked once for each client that received the message.

So:

# main.py
import random
from flask import Flask, send_from_directory
from flask_socketio import SocketIO, emit

app = Flask(__name__)
app.config["SECRET_KEY"] = "secret!"
socketio = SocketIO(app)


# Create a route for the index page (http://localhost:5000/)
@app.route("/")
def root():
    return send_from_directory(".", "index.html")

# Start listening for connecting clients
@socketio.on("connect")
def handle_connect():
    print("Client connected")

# Create a function to act as an ack function
def ack_random_number_received(data):
    print("The client received the random number!", data)

# Start listening for "some_event" events
@socketio.on("some_event")
def handle_some_event():

    # Create a random number (just for demo purposes)
    random_number = random.randint(0, 10)

    # Registering a "callback" function here will act as an ack function
    emit("random_number_picked", random_number, callback=ack_random_number_received)

    # Returning here will send data (a string in this case) to the ack function in JS
    return "Ack from Python"


if __name__ == "__main__":
    socketio.run(app, debug=True)
<!-- index.html -->
<html>
    <head>
        <title>My page</title>
    </head>
    <body>
        <p>The random number is: <span id="random-number">...</span></p>

        <script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js" integrity="sha256-yr4fRk/GU1ehYJPAs8P4JlTgu0Hdsp4ZKrx8bDEDC3I=" crossorigin="anonymous"></script>
        <script type="text/javascript" charset="utf-8">

            // Connect to the server
            var socket = io();

            socket.on('connect', function() {
                console.group('Event: connect');
                console.log('Emit "some_event"');
                socket.emit('some_event', {somedata: 123}, function(ack) {
                    console.group('Ack function triggered for "some_event"');
                    console.log('The server acknowledged our event, this is the response:', ack);
                    console.groupEnd();
                });
                console.groupEnd();
            });

            // Listen for events
            socket.on('random_number_picked', function(newNumber, callback) {

                // Add some logging
                console.group('Event: random_number_picked');
                console.log('The new random number is', newNumber);
                console.log('The ack function is', callback);

                // Update a part of the page
                document.getElementById("random-number").innerHTML = newNumber;

                // Invoke the callback function to send an ack to Python
                callback("Ack from JS");
                console.groupEnd();
            });

        </script>
    </body>
</html>

Browser console log

Python console log

Gijs Wobben
  • 1,974
  • 1
  • 10
  • 13
  • i dont see any description of ack function in that doc; only event handlers – Dee Nov 26 '20 at 03:52
  • 1
    @datdinhquoc, it's really there.. Anyway, I've updated my answer with a full working example. Hope that helps – Gijs Wobben Nov 26 '20 at 09:05
  • This is a great example. That 2nd arg, 'callback', on the js side event handler function was very unclear to me that it was a predefined function your handler was going to be passed by the system. This cleared it up and now I have it working. – user184190 Nov 02 '22 at 16:14
0

Just to simplify the answer by Gijs Wobben:

Client side:

sio.emit("eventname",data,function ackfunc(ackval){
     console.log(ackval);
});

Server side:

def eventname_func(sid,data):
    ...
    return ackval # This be thrown to ackfunc at client

sio.on("eventname",eventname_func)
Dee
  • 7,455
  • 6
  • 36
  • 70