[Libwebsockets] Synchronous API wrapping libwebsockets?

Duy Lan Nguyen ndlan2k at gmail.com
Sun Nov 9 21:07:47 CET 2014


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?


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.


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
> >>
> >>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://libwebsockets.org/pipermail/libwebsockets/attachments/20141109/419c67e3/attachment-0001.html>


More information about the Libwebsockets mailing list