[Libwebsockets] Synchronous API wrapping libwebsockets?

Andy Green andy at warmcat.com
Sun Nov 9 21:24:00 CET 2014



On 10 November 2014 04:07:47 GMT+08:00, Duy Lan Nguyen <ndlan2k at gmail.com> wrote:
>Some more questions
>
>1.
>So I can do this instead, right?
>
>case LWS_CALLBACK_CLIENT_WRITEABLE:
>
>- Call libwebsocket_write() to send current SendRequest.Data in the
>queue,
>if there is any.
>
>- Remove the current SendRequest in the queue.
>
>- Throw the SendRequest.CompleteEvent.
>
>
>2.
>
>I do this experiment on client. The server is supposed to receive the
>"Hello world" and send it back.
>
>
>case LWS_CALLBACK_CLIENT_RECEIVE:
>
>fprintf(stderr, "callback_simple: LWS_CALLBACK_CLIENT_RECEIVE\n");
>
>((char *)in)[len] = '\0';
>
>fprintf(stderr, "rx %d '%s'\n", (int)len, (char *)in);
>
>was_closed = 1;
>
>break;
>
>
>case LWS_CALLBACK_CLIENT_WRITEABLE:
>
>fprintf(stderr, "callback_simple: LWS_CALLBACK_CLIENT_WRITEABLE\n");
>
>l += sprintf((char *)&buf[LWS_SEND_BUFFER_PRE_PADDING + l],
>
>"Hello world");
>
>
>fprintf(stderr, "Before Write %d bytes of %d-byte buffer: %s\n", n, l,
>&buf[LWS_SEND_BUFFER_PRE_PADDING]);
>
>
>n = libwebsocket_write(wsi,
>
>&buf[LWS_SEND_BUFFER_PRE_PADDING], l, opts | LWS_WRITE_BINARY);
>
>
>fprintf(stderr, "After Write %d bytes of %d-byte buffer: %s\n", n, l,
>&buf[LWS_SEND_BUFFER_PRE_PADDING]);
>
>
>if (n < 0)
>
>return -1;
>
>if (n < l) {
>
>lwsl_err("Partial write LWS_CALLBACK_CLIENT_WRITEABLE\n");
>
>return -1;
>
>}
>
>
>libwebsocket_callback_on_writable(context, wsi);
>
>break;
>
>But the client output is as follows
>
>
>callback_simple: LWS_CALLBACK_CLIENT_ESTABLISHED
>
>callback_simple: LWS_CALLBACK_CLIENT_WRITEABLE
>
>Before Write 0 bytes of 12-byte buffer: Hello world
>
>After Write 12 bytes of 12-byte buffer: √├╖P▄å¼S┴╩┐6
>
>callback_simple: LWS_CALLBACK_CLIENT_WRITEABLE
>
>Before Write 0 bytes of 12-byte buffer: Hello world
>
>After Write 12 bytes of 12-byte buffer: ╧iR⌡Φ,I÷⌡`Zô
>
>callback_simple: LWS_CALLBACK_CLOSED
>
>
>That means the LWS_CALLBACK_CLIENT_RECEIVE has been missed. And
>LWS_CALLBACK_CLIENT_WRITEABLE
>has been called twice, but as I check the server side just receives 1
>"Hello world".
>
>
>So what is wrong here?

Maybe nothing... how about your writeable request is serviced, you ask for another one and then close the connection before any data was received?

>
>Also, back to the synchronous Send(), if I just do as in 1. above, I'm
>afraid that the SendRequest.CompleteEvent may be thrown too early,
>before
>libwebsocket_write() actually completed. My "complete" means that the
>TCP
>layer underneath has finished sending successfully.

You need to be more precise.  Because a write() on the socket returning does not mean the data got anywhere near the network interface.

-Andy

>
>Is that right?
>
>
>3.
>
>For Recv(DataBuffer), as mentioned, for callback (...void *in, size_t
>len)
>
>case LWS_CALLBACK_CLIENT_RECEIVE:
>
>- Pass received data to RecvRequest.DataBuffer in the queue, if there
>is
>any.
>
>- Remove the current RecvRequest in the queue.
>
>- Throw the its RecvRequest.CompleteEvent.
>
>Should I pass pointer of in and len to DataBuffer, or should I memcpy
>in
>and len to DataBuffer?
>
>Many thanks,
>Lan
>
>
>On Sat, Nov 8, 2014 at 9:15 PM, Andy Green <andy at warmcat.com> wrote:
>
>>
>>
>> On 9 November 2014 13:00:48 GMT+08:00, Duy Lan Nguyen
><ndlan2k at gmail.com>
>> wrote:
>> >Some things I'm still not clear about:
>> >
>> >1.
>> >>case LWS_CALLBACK_CLIENT_WRITEABLE:
>> >>
>> >>- Throw the previous SendRequest.CompleteEvent, if there is any.
>> >>
>> >>- Call libwebsocket_write() to send current SendRequest.Data in the
>> >>queue,
>> >>if there is any.
>> >>
>> >>- Remove the current SendRequest in the queue to be the "previous"
>> >one.
>> >>
>> >>- Call libwebsocket_callback_on_writable()
>> >
>> >A> You would only do the last bit if there was more to send on that
>> >connection already.
>> >
>> >A> Otherwise you would just return 0 and let it go quiet there until
>> >the
>> >other thread saw something came for that connection to deal with.
>> >
>> >I need to notify the Send() call that libwebsocket_write() has
>> >completed
>> >successfully so that the Send() stops blocking and returns
>> >successfully.
>> >How do I know when libwebsocket_write() has completed successfully,
>to
>> >throw SendRequest.CompleteEvent for that Send()?
>>
>> Depends what you mean by 'completed'... if you mean the work of the
>user
>> code was finished, then it's enough when the libwebsocket_write
>returns for
>> the last bit you were trying to send.
>>
>> If you mean that the other side received it all, that's something
>> completely different, the other side has to send something back to
>confirm.
>>
>> lws might cache part of what you sent and require the socket to be
>> writable more times before it is all sent.  That stuff is handled
>invisibly
>> by the library, but to let it work you have to continuously be doing
>the
>> service loop.
>>
>> >A> You either have to deal with keeping your own list of active wsi,
>in
>> >order to have the right wsi for the data when you call
>> >libwebsocket_callback_on_writable(), or call ..._all_protocol() from
>> >the
>> >other thread if that is what your app is doing.
>> >
>> >A> You can hook ESTABLISHED and CLOSE callbacks to maintain your own
>> >wsi
>> >list if that's what you need.
>> >
>> >I thought there is only 1 wsi returned from
>> >libwebsocket_client_connect()
>> >(just called once in Connect()) to pass around. Could you please
>> >explain
>> >this a bit?
>>
>> Even if you only have the one wsi, you still have races where
>>
>>  - the connection or ws handshake did not complete yet -- the wsi is
>live
>> but not usable
>>
>>  - the library decides to close and free your client connection, but
>the
>> other thread continues to hold the now-dead wsi pointer
>>
>> So you still need to handle CLIENT_ESTABLISHED and CLOSED callbacks
>to
>> manage flagging the connection as usable by the other thread.
>>
>> -Andy
>>
>> >Many thanks,
>> >Lan
>> >
>> >
>> >
>> >
>> >On Sat, Nov 8, 2014 at 5:22 PM, Andy Green <andy at warmcat.com> wrote:
>> >
>> >>
>> >>
>> >> On 9 November 2014 07:55:07 GMT+08:00, Duy Lan Nguyen
>> ><ndlan2k at gmail.com>
>> >> wrote:
>> >> >Hello,
>> >> >
>> >> >Appreciate if you could help. I'm trying to implement a simple
>> >> >Synchronous
>> >> >API wrapping libwebsockets (for client side, not server side),
>> >roughly
>> >> >as
>> >> >follows.
>> >> >
>> >> >MYSOCK = Connect(...);
>> >> >
>> >> >STATUS Send(MYSOCK, char* pbData, uint cbData, uint dwFlags);
>> >> >
>> >> >STATUS Receive(MYSOCK, char* pbData, uint cbData, uint dwFlags);
>> >> >
>> >> >
>> >> >Close(MYSOCK);
>> >>
>> >> Well, okay.  That's not the idea of lws I guess you already know.
>> >>
>> >> >DO YOU HAVE any ADVICE on HOW to do that most efficiently?
>> >> >
>> >> >
>> >> >
>> >> >I actually have the following design
>> >> >
>> >> >
>> >> >A global queue of RecvRequest struct
>> >> >
>> >> >A global queue of SendRequest struct
>> >> >
>> >> >
>> >> >Connect():
>> >> >
>> >> >Create a separate thread
>> >> >
>> >> >- calling libwebsocket_create_context()
>> >> >
>> >> >- calling libwebsocket_client_connect()
>> >> >
>> >> >- running the loop libwebsocket_service()
>> >>
>> >> OK.
>> >>
>> >> >Close():
>> >> >
>> >> >Just shutdown the above thread and callings properly
>> >> >
>> >> >
>> >> >Send():
>> >> >
>> >> >Add its SendRequest struct to the queue
>> >> >
>> >> >Call libwebsocket_callback_on_writable()
>> >> >
>> >> >Wait for its event SendRequest.CompleteEvent
>> >> >
>> >> >return STATUS
>> >> >
>> >> >
>> >> >Receive():
>> >> >
>> >> >Add its RecvRequest struct to the queue
>> >> >
>> >> >Wait for its event RecvRequest.CompleteEvent
>> >> >
>> >> >return STATUS
>> >> >
>> >> >
>> >> >CallBack():
>> >> >
>> >> >case LWS_CALLBACK_CLIENT_WRITEABLE:
>> >> >
>> >> >- Throw the previous SendRequest.CompleteEvent, if there is any.
>> >> >
>> >> >- Call libwebsocket_write() to send current SendRequest.Data in
>the
>> >> >queue,
>> >> >if there is any.
>> >> >
>> >> >- Remove the current SendRequest in the queue to be the
>"previous"
>> >one.
>> >> >
>> >> >- Call libwebsocket_callback_on_writable()
>> >>
>> >> You would only do the last bit if there was more to send on that
>> >> connection already.
>> >>
>> >> Otherwise you would just return 0 and let it go quiet there until
>the
>> >> other thread saw something came for that connection to deal with.
>> >>
>> >> >case LWS_CALLBACK_CLIENT_RECEIVE:
>> >> >
>> >> >- Pass received data to RecvRequest.Data in the queue, if there
>is
>> >any.
>> >> >
>> >> >- Remove the current RecvRequest in the queue.
>> >> >
>> >> >- Throw the its RecvRequest.CompleteEvent.
>> >> >
>> >> >
>> >> >
>> >> >DO YOU have any COMMENT on this design?
>> >>
>> >> You either have to deal with keeping your own list of active wsi,
>in
>> >order
>> >> to have the right wsi for the data when you call
>> >> libwebsocket_callback_on_writable(), or call ..._all_protocol()
>from
>> >the
>> >> other thread if that is what your app is doing.
>> >>
>> >> You can hook ESTABLISHED and CLOSE callbacks to maintain your own
>wsi
>> >list
>> >> if that's what you need.
>> >>
>> >> Basically your design should be OK for lws, you're only writing
>from
>> >the
>> >> service thread in the writable callback, and from the other thread
>> >you only
>> >> do the on_writable() call, these are the key things to get a good
>> >result if
>> >> there's more than one thread or process involved.
>> >>
>> >> -Andy
>> >>
>> >> >
>> >> >
>> >> >Many thanks,
>> >> >
>> >> >Lan
>> >> >
>> >> >
>> >>
>>
>>>------------------------------------------------------------------------
>> >> >
>> >> >_______________________________________________
>> >> >Libwebsockets mailing list
>> >> >Libwebsockets at ml.libwebsockets.org
>> >> >http://ml.libwebsockets.org/mailman/listinfo/libwebsockets
>> >>
>> >>
>>
>>




More information about the Libwebsockets mailing list