[nanomsg] Re: Asynchronous (raw) sockets in nanomsg

  • From: Paul Colomiets <paul@xxxxxxxxxxxxxx>
  • To: "nanomsg@xxxxxxxxxxxxx" <nanomsg@xxxxxxxxxxxxx>
  • Date: Mon, 18 Nov 2013 21:55:57 +0200

Hi Martin,

On Mon, Nov 18, 2013 at 9:35 PM, Martin Sustrik <sustrik@xxxxxxxxxx> wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On 18/11/13 20:22, Paul Colomiets wrote:
>> Hi Martin,
>>
>> On Mon, Nov 18, 2013 at 9:08 PM, Martin Sustrik
>> <sustrik@xxxxxxxxxx> wrote:
>>> Ok. Let me give an example:
>>>
>>> // Open the connection to server. s = nn_socket (AF_SP, NN_REQ);
>>> nn_connect (s, "tcp://myserver:5555");
>>>
>>> // Send first request. Associate it with dummy request context
>>> (simple int). const int first = 1; nn_req_send (s, &first, "ABC",
>>> 3, 0);
>>>
>>> //  Second request. Give it a different dummy context. const int
>>> second = 2; nn_req_send (s, &second, "DEF", 3, 0);
>>>
>>> //  Wait for a reply. int *context; char reply [32]; nn_req_recv
>>> (s, &context, buf, sizeof (buf), 0);
>>>
>>> //  Check which reply was received. if (context == &first)
>>
>> 1. Shouldn't be compared by value? In case of comparison by
>> pointer it's possible to make the following mistake:
>>
>> int request_id = 1; nn_req_send(s, &request_id..); req->request_id
>> = request_id; return req;
>
> It's just a dummy context. In real world I would expect the code to
> look something like:
>
> struct mycontext {
>    int a;
>    int b;
>    int c;
> }
>
> mycontext context1 = {1, 2, 3};
> nn_send (s, &context1, "ABC", 3, 0);
>
> mycontext *ctx;
> nn_recv (s, &ctx, buf, sizeof (buf), 0);
> if (ctx == &context1) ...
>
> etc.
>

You have same error here. You almost certainly never want to get the
value on the stack in asynchronous loop, since return from this code
causes pointer to be invalidated. Your code makes sense only when you
do a single/multiple requests without falling back to the main loop.
And in this case you almost certainly want the cancel callback, so you
can cancel request before ``return``ing this function (e.g. in case of
some error between nn_send and nn_recv)

>> 2. How to know that request is timed out?
>>
>> rc = nn_req_recv(s, &context, buf, sizeof(buf), 0); if(rc < 0 &&
>> errno == ETIMEDOUT) { printf("request %d timed out\n", *context);
>> }
>>
>> Is it ok that context is filled even if error code received?
>> Probably only certain errors will have request id filled in?
>
> Looks ugly, but it's technically viable.
>

kinda, yes

> The other option, of course, is not to have timeouts and let the use
> cancel the requests:
>
> nn_req_cancel (s, &context1);
>

That would:

1. require every user to implement timeout management

2. will leak memory since many users will forget about that

The #1 is likely be easy when using some async main loop. But is ugly
when you have a blocking code which just run multiple requests
simultaneously.

I.e. I'm almost certain that both timeout and cancel are needed.

-- 
Paul

Other related posts: