[Libwebsockets] how to send a message to all connected clients?

Andy Green andy at warmcat.com
Mon Jan 26 14:19:52 CET 2015



On 26 January 2015 20:25:58 GMT+08:00, Glaudiston Gomes da Silva <glaudistong at gmail.com> wrote:
>Hi Andy,
>
>Thanks, it worked. but how to send a specific message to all connected
>sockets? I've looked into samples and it using static pool ring. I
>don't think it's effective because it stores only N messages and may
>be replaced before all clients receive it.

There's a basic problem that on a real network, clients may go away and come back in terms of reachability randomly.  For example, a guy on LTE goes in a big tunnel and will not receive anything until he comes out the other side.

If the tunnel is a few metres it's no big deal but if it's several minutes he is gone, or his phone drops in the sea and he never comes back, these are situations where the server can't just increase the buffer size to get around it, at some point the buffering has to accept its relationship with that remote peer has broken down and deal with him as a disconnect or a logical automatic reconnect.

So for that reason if everyone is trying to get the same data, a ring buffer can be a good solution, if the individual clients can detect that since their last sent data, the ring buffer "overflowed" from their point of view and they need to do something drastic then.

>I'm thinking in set a queue in each user (per_session_data) and
>interate all to append message in each queue.
>
>Is there a better way ?

The basic thing is in lws you can only generically trigger each connection to understand it could send something (when it actually could send something, which may be at quite different times for each connection).  You have to use your own information in your user code to figure out what it is that should be sent on each connection if anything.  That 'split' is in a good place because then it's super flexible in terms of how the decisions of what to send are managed by user code.

How to best do that in the user code is all about exactly what you're trying to send.  But generally, clients may drop and join randomly anyway, and as explained they may "go away" temporarily but for unreasonable periods, which sometimes is best handled by forcing a drop and reconnect rather than endless buffering.... he could drop and reconnect himself at any time anyway so why not re-use your arrangements for that to solve unreasonable per-connection buffering...

-Andy

>- Ton
>2015-01-25 21:23 GMT-02:00 Andy Green <andy at warmcat.com>:
>>
>>
>> On 26 January 2015 04:43:24 GMT+08:00, Glaudiston Gomes da Silva
><glaudistong at gmail.com> wrote:
>>>Hello,
>>>
>>>I'm trying to use libwebsockets in my application as server, for this
>>>I'm using the echo test as sample code, for client-server
>>>communication, all get well, but  I'm trying to do a function that
>>>notify all connected clients sockets when a new client arrive or
>>>leave.
>>>
>>>My code runs ok on first connection and notify the client, but on
>>>second one it generate a seg fault. I think may be the library
>>>provides me a nice way to do this. but here my code:
>>
>> The api that solves this for you cleanly is
>>
>> int
>> libwebsocket_callback_on_writable_all_protocol(
>>                                  const struct libwebsocket_protocols
>*protocol);
>>
>> Every active, established connection will receive the WRITEABLE
>callback when he can accept more data on his connection.
>>
>> Have a look at the test server sources for how it sends the canvas
>drawing data to everyone, and how he has per-connection structs without
>having to allocate or destroy them himself.
>>
>> -Andy
>>
>>>To do this, I do created a struct:
>>>> struct WSSession {
>>>>         struct libwebsocket_context *context;
>>>>         struct libwebsocket *wsi;
>>>> };
>>>>
>>>> int wssession_count=0;
>>>>
>>>> struct WSSession ** wssession;
>>>
>>>and a notify_all function:
>>>> void notify_all(enum libwebsocket_callback_reasons reason){
>>>>         int i, n;
>>>>         for ( i=0; i<wssession_count; i++ ){
>>>>         switch (reason) {
>>>>         case LWS_CALLBACK_ESTABLISHED:
>>>>                 // n = libwebsocket_write(wssession[i]->wsi,
>>>"abcd\0", 5, LWS_WRITE_TEXT);
>>>>
>>>libwebsocket_callback_on_writable(wssession[i]->context,
>>>wssession[i]->wsi);
>>>>                 break;
>>>>         case LWS_CALLBACK_CLOSED:
>>>>                 //int n = libwebsocket_write(wssession[i]->wsi,
>>>&resp.buf[0], resp.len, LWS_WRITE_TEXT);
>>>>                 //
>>>libwebsocket_callback_on_writable(wssession[i]->context,
>>>wssession[i]->wsi);
>>>>                 break;
>>>>         default:
>>>>                 break;
>>>>         }
>>>>         }
>>>> }
>>>
>>>
>>>
>>>So, in callback_echo function I have added the block for
>>>LWS_CALLBACK_ESTABLISHED:
>>>>
>>>> callback_echo(struct libwebsocket_context *context, struct
>>>libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void
>>>*user, void *in, size_t len)
>>>> {
>>>> ...
>>>>         case LWS_CALLBACK_ESTABLISHED:
>>>>                 lwsl_notice("Client connected \n");
>>>>                 struct WSSession ** wsc = realloc( wssession,
>>>sizeof(struct WSSession) * ++wssession_count );
>>>>                 if ( wsc == NULL ) {
>>>>                         lwsl_err("ERROR Fail to realloc for
>wssession
>>>number %i, hanging up.\n", wssession_count );
>>>>                         return 1;
>>>>                 }
>>>>                 wssession=wsc;
>>>>
>>>>                 wssession[wssession_count-1]->context=context;
>>>>                 wssession[wssession_count-1]->wsi=wsi;
>>>>                 notify_all(reason);
>>>>                 break;
>>>
>>>
>>>Anyone can help me understand why it's wrong and what is the correct
>>>way to do it ?
>>>_______________________________________________
>>>Libwebsockets mailing list
>>>Libwebsockets at ml.libwebsockets.org
>>>http://ml.libwebsockets.org/mailman/listinfo/libwebsockets
>>




More information about the Libwebsockets mailing list