<div dir="ltr"><div>Some more questions</div><div><br></div>1.<div>So I can do this instead, right?</div><div><br></div><div><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px">case LWS_CALLBACK_CLIENT_WRITEABLE:<br></p><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px">- Call libwebsocket_write() to send current SendRequest.Data in the queue, if there is any.<br></p><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px">- Remove the current SendRequest in the queue.</p><p class="MsoNormal" style="font-size:13px;font-family:arial,sans-serif">- Throw the SendRequest.CompleteEvent.</p><p class="MsoNormal" style="font-size:13px;font-family:arial,sans-serif"><br></p><p class="MsoNormal" style="font-size:13px;font-family:arial,sans-serif">2.</p><p class="MsoNormal" style="font-size:13px;font-family:arial,sans-serif">I do this experiment on client. The server is supposed to receive the "Hello world" and send it back.</p><p class="MsoNormal" style="font-size:13px;font-family:arial,sans-serif"><br></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">   </span>case LWS_CALLBACK_CLIENT_RECEIVE:</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">                </span>fprintf(stderr, "callback_simple: LWS_CALLBACK_CLIENT_RECEIVE\n");</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">             </span>((char *)in)[len] = '\0';</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">                </span>fprintf(stderr, "rx %d '%s'\n", (int)len, (char *)in);</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">         </span>was_closed = 1;</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">          </span>break;</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><br></font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">        </span>case LWS_CALLBACK_CLIENT_WRITEABLE:</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">              </span>fprintf(stderr, "callback_simple: LWS_CALLBACK_CLIENT_WRITEABLE\n");</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">           </span>l += sprintf((char *)&buf[LWS_SEND_BUFFER_PRE_PADDING + l],</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">                  </span>"Hello world");</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><br></font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">             </span>fprintf(stderr, "Before Write %d bytes of %d-byte buffer: %s\n", n, l, &buf[LWS_SEND_BUFFER_PRE_PADDING]);</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><br></font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">              </span>n = libwebsocket_write(wsi,</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">                      </span>&buf[LWS_SEND_BUFFER_PRE_PADDING], l, opts | LWS_WRITE_BINARY);</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><br></font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">           </span>fprintf(stderr, "After Write %d bytes of %d-byte buffer: %s\n", n, l, &buf[LWS_SEND_BUFFER_PRE_PADDING]);</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><br></font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">               </span>if (n < 0)</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">                    </span>return -1;</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">               </span>if (n < l) {</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">                  </span>lwsl_err("Partial write LWS_CALLBACK_CLIENT_WRITEABLE\n");</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">                     </span>return -1;</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">               </span>}</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><br></font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">             </span>libwebsocket_callback_on_writable(context, wsi);</font></p><p class="MsoNormal" style><font face="arial, sans-serif"><span class="" style="white-space:pre">         </span>break;</font></p><div><br></div><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px">But the client output is as follows</p><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px"><br></p><p class="MsoNormal" style><font face="arial, sans-serif">callback_simple: LWS_CALLBACK_CLIENT_ESTABLISHED</font></p><p class="MsoNormal" style><font face="arial, sans-serif">callback_simple: LWS_CALLBACK_CLIENT_WRITEABLE</font></p><p class="MsoNormal" style><font face="arial, sans-serif">Before Write 0 bytes of 12-byte buffer: Hello world</font></p><p class="MsoNormal" style><font face="arial, sans-serif">After Write 12 bytes of 12-byte buffer: √├╖P▄å¼S┴╩┐6</font></p><p class="MsoNormal" style><span style="font-family:arial,sans-serif">callback_simple: LWS_CALLBACK_CLIENT_WRITEABLE</span><br></p><p class="MsoNormal" style><font face="arial, sans-serif">Before Write 0 bytes of 12-byte buffer: Hello world</font></p><p class="MsoNormal" style><font face="arial, sans-serif">After Write 12 bytes of 12-byte buffer: ╧iR⌡Φ,I÷⌡`Zô</font></p><p class="MsoNormal" style><font face="arial, sans-serif">callback_simple: LWS_CALLBACK_CLOSED</font></p><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px"><br></p><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px">That means the <span style="font-size:small">LWS_CALLBACK_CLIENT_RECEIVE has been missed. And </span><span style="font-size:small">LWS_CALLBACK_CLIENT_WRITEABLE has been called twice, but as I check the server side just receives 1 "Hello world".</span></p><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px"><span style="font-size:small"><br></span></p><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px"><span style="font-size:small">So what is wrong here?</span></p><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px"><span style="font-size:small"><br></span></p><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px"><span style="font-size:small">Also, back to the synchronous Send(), if I just do as in 1. above, I'm afraid that </span>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.</p><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px"><br></p><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px">Is that right?</p><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px"><br></p><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px">3.</p><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px">For Recv(DataBuffer), as mentioned, for callback (...void *in, size_t len)</p><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px">case LWS_CALLBACK_CLIENT_RECEIVE:<br></p><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px">- Pass received data to RecvRequest.DataBuffer in the queue, if there is any.</p><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px">- Remove the current RecvRequest in the queue.</p><p class="MsoNormal" style="font-family:arial,sans-serif;font-size:13px">- Throw the its RecvRequest.CompleteEvent.</p><div><br></div><div>Should I pass pointer of in and len to DataBuffer, or should I memcpy in and len to DataBuffer?</div><div><br></div><div>Many thanks,</div><div>Lan</div></div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Sat, Nov 8, 2014 at 9:15 PM, Andy Green <span dir="ltr"><<a href="mailto:andy@warmcat.com" target="_blank">andy@warmcat.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class=""><br>
<br>
On 9 November 2014 13:00:48 GMT+08:00, Duy Lan Nguyen <<a href="mailto:ndlan2k@gmail.com">ndlan2k@gmail.com</a>> wrote:<br>
>Some things I'm still not clear about:<br>
><br>
>1.<br>
>>case LWS_CALLBACK_CLIENT_WRITEABLE:<br>
>><br>
>>- Throw the previous SendRequest.CompleteEvent, if there is any.<br>
>><br>
>>- Call libwebsocket_write() to send current SendRequest.Data in the<br>
>>queue,<br>
>>if there is any.<br>
>><br>
>>- Remove the current SendRequest in the queue to be the "previous"<br>
>one.<br>
>><br>
>>- Call libwebsocket_callback_on_writable()<br>
><br>
>A> You would only do the last bit if there was more to send on that<br>
>connection already.<br>
><br>
>A> Otherwise you would just return 0 and let it go quiet there until<br>
>the<br>
>other thread saw something came for that connection to deal with.<br>
><br>
>I need to notify the Send() call that libwebsocket_write() has<br>
>completed<br>
>successfully so that the Send() stops blocking and returns<br>
>successfully.<br>
>How do I know when libwebsocket_write() has completed successfully, to<br>
>throw SendRequest.CompleteEvent for that Send()?<br>
<br>
</span>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.<br>
<br>
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.<br>
<br>
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.<br>
<span class=""><br>
>A> You either have to deal with keeping your own list of active wsi, in<br>
>order to have the right wsi for the data when you call<br>
>libwebsocket_callback_on_writable(), or call ..._all_protocol() from<br>
>the<br>
>other thread if that is what your app is doing.<br>
><br>
>A> You can hook ESTABLISHED and CLOSE callbacks to maintain your own<br>
>wsi<br>
>list if that's what you need.<br>
><br>
>I thought there is only 1 wsi returned from<br>
>libwebsocket_client_connect()<br>
>(just called once in Connect()) to pass around. Could you please<br>
>explain<br>
>this a bit?<br>
<br>
</span>Even if you only have the one wsi, you still have races where<br>
<br>
 - the connection or ws handshake did not complete yet -- the wsi is live but not usable<br>
<br>
 - the library decides to close and free your client connection, but the other thread continues to hold the now-dead wsi pointer<br>
<br>
So you still need to handle CLIENT_ESTABLISHED and CLOSED callbacks to manage flagging the connection as usable by the other thread.<br>
<span class="HOEnZb"><font color="#888888"><br>
-Andy<br>
</font></span><div class="HOEnZb"><div class="h5"><br>
>Many thanks,<br>
>Lan<br>
><br>
><br>
><br>
><br>
>On Sat, Nov 8, 2014 at 5:22 PM, Andy Green <<a href="mailto:andy@warmcat.com">andy@warmcat.com</a>> wrote:<br>
><br>
>><br>
>><br>
>> On 9 November 2014 07:55:07 GMT+08:00, Duy Lan Nguyen<br>
><<a href="mailto:ndlan2k@gmail.com">ndlan2k@gmail.com</a>><br>
>> wrote:<br>
>> >Hello,<br>
>> ><br>
>> >Appreciate if you could help. I'm trying to implement a simple<br>
>> >Synchronous<br>
>> >API wrapping libwebsockets (for client side, not server side),<br>
>roughly<br>
>> >as<br>
>> >follows.<br>
>> ><br>
>> >MYSOCK = Connect(...);<br>
>> ><br>
>> >STATUS Send(MYSOCK, char* pbData, uint cbData, uint dwFlags);<br>
>> ><br>
>> >STATUS Receive(MYSOCK, char* pbData, uint cbData, uint dwFlags);<br>
>> ><br>
>> ><br>
>> >Close(MYSOCK);<br>
>><br>
>> Well, okay.  That's not the idea of lws I guess you already know.<br>
>><br>
>> >DO YOU HAVE any ADVICE on HOW to do that most efficiently?<br>
>> ><br>
>> ><br>
>> ><br>
>> >I actually have the following design<br>
>> ><br>
>> ><br>
>> >A global queue of RecvRequest struct<br>
>> ><br>
>> >A global queue of SendRequest struct<br>
>> ><br>
>> ><br>
>> >Connect():<br>
>> ><br>
>> >Create a separate thread<br>
>> ><br>
>> >- calling libwebsocket_create_context()<br>
>> ><br>
>> >- calling libwebsocket_client_connect()<br>
>> ><br>
>> >- running the loop libwebsocket_service()<br>
>><br>
>> OK.<br>
>><br>
>> >Close():<br>
>> ><br>
>> >Just shutdown the above thread and callings properly<br>
>> ><br>
>> ><br>
>> >Send():<br>
>> ><br>
>> >Add its SendRequest struct to the queue<br>
>> ><br>
>> >Call libwebsocket_callback_on_writable()<br>
>> ><br>
>> >Wait for its event SendRequest.CompleteEvent<br>
>> ><br>
>> >return STATUS<br>
>> ><br>
>> ><br>
>> >Receive():<br>
>> ><br>
>> >Add its RecvRequest struct to the queue<br>
>> ><br>
>> >Wait for its event RecvRequest.CompleteEvent<br>
>> ><br>
>> >return STATUS<br>
>> ><br>
>> ><br>
>> >CallBack():<br>
>> ><br>
>> >case LWS_CALLBACK_CLIENT_WRITEABLE:<br>
>> ><br>
>> >- Throw the previous SendRequest.CompleteEvent, if there is any.<br>
>> ><br>
>> >- Call libwebsocket_write() to send current SendRequest.Data in the<br>
>> >queue,<br>
>> >if there is any.<br>
>> ><br>
>> >- Remove the current SendRequest in the queue to be the "previous"<br>
>one.<br>
>> ><br>
>> >- Call libwebsocket_callback_on_writable()<br>
>><br>
>> You would only do the last bit if there was more to send on that<br>
>> connection already.<br>
>><br>
>> Otherwise you would just return 0 and let it go quiet there until the<br>
>> other thread saw something came for that connection to deal with.<br>
>><br>
>> >case LWS_CALLBACK_CLIENT_RECEIVE:<br>
>> ><br>
>> >- Pass received data to RecvRequest.Data in the queue, if there is<br>
>any.<br>
>> ><br>
>> >- Remove the current RecvRequest in the queue.<br>
>> ><br>
>> >- Throw the its RecvRequest.CompleteEvent.<br>
>> ><br>
>> ><br>
>> ><br>
>> >DO YOU have any COMMENT on this design?<br>
>><br>
>> You either have to deal with keeping your own list of active wsi, in<br>
>order<br>
>> to have the right wsi for the data when you call<br>
>> libwebsocket_callback_on_writable(), or call ..._all_protocol() from<br>
>the<br>
>> other thread if that is what your app is doing.<br>
>><br>
>> You can hook ESTABLISHED and CLOSE callbacks to maintain your own wsi<br>
>list<br>
>> if that's what you need.<br>
>><br>
>> Basically your design should be OK for lws, you're only writing from<br>
>the<br>
>> service thread in the writable callback, and from the other thread<br>
>you only<br>
>> do the on_writable() call, these are the key things to get a good<br>
>result if<br>
>> there's more than one thread or process involved.<br>
>><br>
>> -Andy<br>
>><br>
>> ><br>
>> ><br>
>> >Many thanks,<br>
>> ><br>
>> >Lan<br>
>> ><br>
>> ><br>
>><br>
>>------------------------------------------------------------------------<br>
>> ><br>
>> >_______________________________________________<br>
>> >Libwebsockets mailing list<br>
>> ><a href="mailto:Libwebsockets@ml.libwebsockets.org">Libwebsockets@ml.libwebsockets.org</a><br>
>> ><a href="http://ml.libwebsockets.org/mailman/listinfo/libwebsockets" target="_blank">http://ml.libwebsockets.org/mailman/listinfo/libwebsockets</a><br>
>><br>
>><br>
<br>
</div></div></blockquote></div><br></div>