Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emitting to specific client #89

Closed
ericremoreynolds opened this issue Jan 23, 2015 · 10 comments
Closed

Emitting to specific client #89

ericremoreynolds opened this issue Jan 23, 2015 · 10 comments

Comments

@ericremoreynolds
Copy link

Hello Miguel,

In the JavaScript socket.io server there are a couple of ways to emit to a specific client, even from outside of the client's context:
a) socket.emit
b) emit to the room named "Socket#id" where id is a unique client id

I was wondering how this can be achieved with Flask-socket.io? Would option (b) apply? If so how can I obtain the client id?

Best regards,

Eric

@ericremoreynolds
Copy link
Author

I made this gist and it seems to work.

But I don't know if this approach is OK or if using it in production will create problems?

@miguelgrinberg
Copy link
Owner

@ericremoreynolds your solution will work just fine, but has the undesirable feature that you use gevent-socketio internals. My preference is to use the following procedure:

  • Before the client connects, I log in the user to the application, using normal HTTP process (i.e. Flask-Login)
  • Once the user is logged in, I write his/her ID to session. The ID is stored in the session by Flask-Login, but again, to avoid looking into internal structures of other modules, I write my own copy. Note that this is an ID that my application generated for the user, for example its database primary key.
  • When the client opens the socket connection, you can access the session variable in the connect event, and put the user in a room name based on the ID.
  • Use socketio.emit(..., room=<user_room>) to emit to a specific customer.

Hope this helps.

@jeffjzx
Copy link

jeffjzx commented Jan 31, 2015

Hi miguelgrinberg, i'm reading your example code about room, but when i press "send to room" button, nothing show up on my browser(i have already joined a room), can you please tell me how to deal with it? Thank you.

@miguelgrinberg
Copy link
Owner

@jeffjzx did you write a room name before clicking the join and send buttons? What name did you use?

@jeffjzx
Copy link

jeffjzx commented Feb 1, 2015

Oops, sorry, i realize that i have used the forms in wrong order. Thank you for your reply..

@richburdon
Copy link

@miguelgrinberg, first of all: great repo -- thanks for building it.

I think sending to an individual client out of context might be the most typical use case and I think the room work around is a bit limited:

1). It may be desirable not to force clients to authenticate? Also, since the socket itself has a unique identifier can't you expose that (like I believe the socket.io node library?)

2). The "room" workaround is going to "pollute" the set of rooms? Again the node implementation seems to have a more straight-forward API -- isn't something like this possible and natural?

io.sockets.socket(savedSocketId).emit(...)

Thanks,

RB

@miguelgrinberg
Copy link
Owner

1). It may be desirable not to force clients to authenticate?

I don't understand what is the relation between user authentication and this. You can put clients into rooms without authenticating them.

Also, since the socket itself has a unique identifier can't you expose that (like I believe the socket.io node library?)

You can certainly follow this approach if you like. But gevent-socketio does not publicly expose the socket ID, so you need to go find it in its internal data structures.

2). The "room" workaround is going to "pollute" the set of rooms? Again the node implementation seems to have a more straight-forward API -- isn't something like this possible and natural?

The set of rooms is handled internally by the extension, so it should not affect you at all. The memory requirements for a room are fairly small.

I find the node implementation less straightforward. You can address a message to a specific client (via its session ID), or to a room (via a room name) or to all clients (via broadcast.emit function). Three different ways of doing essentially the same thing.

For the upcoming major release of this extension I'm planning to automatically create the individual client rooms. These will be given the name of the session ID, which is exactly what you suggested above.

@richburdon
Copy link

I don't understand what is the relation between user authentication and this.

I may not have understood, but in your answer above you say "Once the user is logged in, I write his/her ID to session"

But gevent-socketio does not publicly expose the socket ID

Again, I probably have misunderstood but isn't the socket ID the "sessid" that is generated by the server (as requried by the protocol: https://github.com/socketio/engine.io-protocol)

https://github.com/abourget/gevent-socketio/blob/master/socketio/virtsocket.py
class Socket(object):
    self.sessid = str(random.random())[2:]

Anyway:

For the upcoming major release... automatically create the individual client rooms

Nice. Do you have an ETA?

But, I still seem to have trouble with the current API: in my app the following line seems to unexpectedly do a broadcast (to unauthenticated apps in different chrome tabs):

socketio.emit(EVENT, message, namespace=NS)

Whereas the following line doesn't emit anything that is picked up by any client:

socketio.emit(EVENT, message, broadcast=True)

And finally (sorry) the socketio docs (http://socket.io/docs/) say that broadcast "means sending a message to everyone else except for the socket that starts it". That seems really odd to me (how could the server then initiate a message to everyone?) Does that explain what I'm seeing above (are you implementing the feature the same way).

Thanks again.

@miguelgrinberg
Copy link
Owner

Closing this issue, as release 1.0 dropped gevent-socketio in favor of a new set of dependencies.

@spectraman
Copy link

Hello Miguel!

Congratulation for your great project, FLASK!
It is a nice and powerful work!
I think can I can help you in debugging of Flask-SocketIO.

I have this small project described below and please tell me if it is suitable for testing / using Flask-SocketIO on server side.

I have a temperature monitoring project, what i use some years ago.
Basically consist from more client units (8 now) and one server. For all units I use Raspberry Pi boards with Raspbian OS.
I can access clients from server localhost, from a specific port or from server public IP via specific port. HTTP protocol was used for server<->client data transfer and login is initiated when connecting to client, on client side.
As an alternative connection is when client units are accessible locally or externally if have their public IP and port forwarding realized of curse. But this alternative isn't used now, so the user connect to client trough server.
For client-server connection I using 'autossh' and seems to be OK, I don't want to change.

Here is a simplified BLOCK diagram:
https://www.facebook.com/spectrasrl/photos/ms.c.eJwzNTE0NTQ0MrI0NjCzsDDUM4XwjY3MTAyMDE0AY3EGMA~-~-.bps.a.538454492945888.1073741848.325515370906469/541511232640214/?type=3&theater

What I want to try it is to have a login option on the server side, and after successful login connect the the respective user to server localhost, port assigned by user ID.

Please tell me if the Flask-SocketIO is the good choice above described requirements.

Thank's in advance for your reply!
Sincerely,
Gyozo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants