Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ReceiveMessageCallback works with sendeventasync only #8

Closed
sarangkalbande opened this issue Dec 26, 2016 · 3 comments
Closed

ReceiveMessageCallback works with sendeventasync only #8

sarangkalbande opened this issue Dec 26, 2016 · 3 comments

Comments

@sarangkalbande
Copy link

Hi All,
I am facing one issue with C SDK,
My requirement is sendingTo and receiveFrom IOTHub should work independently.
But when I verify with sample code unless i send some message to IOT hub receive call back is not invoking.

how can we achieve this behavior using IOT hub client library calls?

@anporumb
Copy link
Contributor

anporumb commented Dec 27, 2016

Hello SarangKalbande,

I've taken iothub_client_sample_amqp and I have removed all code not pertaining to sending messages to IoTHub.

This is DeviceExplorer sending the message
image

This is the application receiving it:
image

And this is the code below

// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include <stdio.h>
#include <stdlib.h>

#include "azure_c_shared_utility/platform.h"
#include "azure_c_shared_utility/threadapi.h"
#include "azure_c_shared_utility/crt_abstractions.h"
#include "iothub_client.h"
#include "iothub_message.h"
#include "iothubtransportamqp.h"

#ifdef MBED_BUILD_TIMESTAMP
#include "certs.h"
#endif // MBED_BUILD_TIMESTAMP

/*String containing Hostname, Device Id & Device Key in the format:                         */
/*  "HostName=<host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>"                */
/*  "HostName=<host_name>;DeviceId=<device_id>;SharedAccessSignature=<device_sas_token>"    */
static const char* connectionString = "DEVICE CONNECTION STRING";

static IOTHUBMESSAGE_DISPOSITION_RESULT ReceiveMessageCallback(IOTHUB_MESSAGE_HANDLE message, void* userContextCallback)
{
    const unsigned char* buffer = NULL;
    size_t size = 0;
    (void)userContextCallback;
    IoTHubMessage_GetByteArray(message, &buffer, &size);
    printf("Received Message with BINARY Data: <<<%.*s>>> & Size=%d\r\n", (int)size, buffer, (int)size);
    return IOTHUBMESSAGE_ACCEPTED;
}

int main(void)
{
    IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle;

    platform_init();
    iotHubClientHandle = IoTHubClient_LL_CreateFromConnectionString(connectionString, AMQP_Protocol);
    IoTHubClient_LL_SetMessageCallback(iotHubClientHandle, ReceiveMessageCallback, NULL);

    /* Now that we are ready to receive commands, let's send some messages */
    do
    {
        IoTHubClient_LL_DoWork(iotHubClientHandle);
        ThreadAPI_Sleep(1);
    } while (1);
            
    IoTHubClient_LL_Destroy(iotHubClientHandle);
    platform_deinit();
}

The example above shows how one receives messages from IoTHub without having to send any to IoTHub.

Can you go into details how the receive call back is not invoking? Thank you.

Best Regards,
Andrei Porumb

@sarangkalbande
Copy link
Author

sarangkalbande commented Dec 28, 2016

Hello Andrei Porumb,
Thanks for this info..Yes Receive callback is working now.
I thought below loop will only take care of sending the messages and was not aware of receiving part also need this.
do
{
IoTHubClient_LL_DoWork(iotHubClientHandle);
ThreadAPI_Sleep(1);
} while (1);

Actually our application has standalone sendto and receivefrom to/fro from cloud
and I was calling IoTHubClient_LL_DoWork in sendto part only.

Do you have any idea of handling this type of scenario?Also the iotHubClientHandle I kept it global and never destroying it on every transaction.

Also wanted to know like can we create multiple handles for send and receive on same connection string ?

@anporumb
Copy link
Contributor

Hello sarangkalbande,

I am happy to hear it is working now. I will try to address your questions.

If you want to restrict receiving from the cloud, then you need to call

IoTHubClient_LL_SetMessageCallback(iotHubClientHandle, NULL, NULL);

(notice the second parameter, the callback, is NULL). If you want to re-enable it, then you need to pass a non-NULL pointer there.

I believe we do not have an explicit way to restrict sending, that is, if the code call IoTHubClient_SendEventAsync then it is (implicitly) understood that the code wants to send something. If there are no calls to IoTHubClient_SendEventAsync then nothing is send.

It is perfectly fine (and actually recommended) to keep iotHubClientHandle alive for the scope of the application, the reason being: if it is created/destroyed for every transaction more traffic than needed is generated (think of TLS handshake for example). If iotHubClientHandle is not destroyed - then TLS is negotiated only once, in the beginning.

Having multiple concurrent handles for sending and receiving on the same connection string is errr... not recommended. There are reasons for that, and I will mention here two of them which should make it obvious why it is not recommended:

  1. 2 physical devices are using the same connection string, the cloud has 1 message intended for the device. Which one of the devices would receive the message?
  2. If a device is connected with a connection string, and another device connects with the same connection string, the first device might have its connection severed by the cloud service.

Best Regards,
Andrei Porumb

I will also close this GitHub issue because I consider the initial issue has been addressed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants