11
votes

I am following Alex Hadik's Flask Socketio tutorial which builds a very simple flask chat app.

http://www.alexhadik.com/blog/2015/1/29/using-socketio-with-python-and-flask-on-heroku

I would like to broadcast a message to all connected users except the sender. I have gone through the flasksocketio init.py but I'm still not sure how to do this.

Here's the server code.

from flask import Flask, render_template,request
from flask.ext.socketio import SocketIO,emit,send
import json,sys

app = Flask(__name__)
socketio = SocketIO(app)
clients = {}
@app.route("/")
def index():
    return render_template('index.html',)

@socketio.on('send_message')
def handle_source(json_data):
    text = json_data['message'].encode('ascii', 'ignore')
    current_client = request.namespace
    current_client_id = request.namespace.socket.sessid
    update_client_list(current_client,current_client_id)
    if clients.keys():
        for client in clients.keys():
            if not current_client_id in client:
                clients[client].socketio.emit('echo', {'echo': 'Server Says: '+text})       

def update_client_list(current_client,current_client_id):
    if not current_client_id in clients: clients[current_client_id] = current_client
    return 

if __name__ == "__main__":
    socketio.run(app,debug = False)

It's currently just broadcasting to all connected clients. I created a connected clients dict (clients) which stores the request.namespace indexed by the client id. Calling clients[client].socketio.emit() for all clients except the sending client still results in the message being broadcast to call users.

Does anyone have any thoughts on how I can broadcast messages to all connected users except the sender?

4
I'm having the same problem and my quick solution (for now) is to have each client generate a 'unique' ID on page load. This ID is included in all calls back to the server. When the server relays the message each client compares this ID to its own to determine if the message was sent by another client or by itself (in which case it will be ignored). It might not be the best solution but it worked for me.Jasper

4 Answers

11
votes

You don't have to save users ids and manage individual emissions, you can specify a broadcast without the sender with emit('my_event', {data:my_data}, broadcast=True, include_self=False). In your case it would be something like this:

@socketio.on('send_message')
    def handle_source(json_data):
        text = json_data['message'].encode('ascii', 'ignore')
        emit('echo', {'echo': 'Server Says: '+text}, broadcast=True, include_self=False)

If you have to send messages for a specific group of clients you can create rooms and then use emit('my_event', {data:my_data}, room=my_room, include_self=False) for sending messages to clients who joined my_room. You can check the reference of flask_socketio.emit for more details.

3
votes

I can't comment on @Alex's response because I don't have enough reputation, but if you want to emit a broadcast message, this is how it is done in Python:

emit('echo', {'data':'what ever you are trying to send'},  broadcast=True)
3
votes

https://flask-socketio.readthedocs.io/en/latest/#flask_socketio.SocketIO.emit

You're looking for the skip_sid parameter for socketio.emit().

skip_sid – The session id of a client to ignore when broadcasting or addressing a room. This is typically set to the originator of the message, so that everyone except that client receive the message. To skip multiple sids pass a list.

0
votes

You can try socket.broadcast.emit instead of socket.emit. I'm not sure if this works in the Python library, but it is the syntax for what you're looking for in Socket.io for Node.js.