Sending and receiving UDP broadcast message in C++ in Windows Phone.

Started by
30 comments, last by frob 6 years, 9 months ago

Only omniscient beings, oracles, and time travelers can help you if you don't post your code...

"datagram sample" two post ealier : https://code.msdn.microsoft.com/windowsapps/DatagramSocket-sample-76a7d82b Scroll is hard?

Pleasse... Do you develop for WinRT platforms? ...

Did you enable broadcast on the socket?
What tool do you use to test whether it "works" or not?
What does Wireshark say about outgoing UDP packets while you're trying to broadcast?

Also, there are more examples of this, such as: http://metronuggets.com/2013/03/18/how-to-send-and-receive-a-udp-broadcast-in-windows-phone-8-and-win8/
If you run this code, does that work? If so, what's different about your own code?

Broadcast is enabled, I check, if I get a message from host in this sample.

I found this tutorial ealier? Did you notice, that this code is in C#? ...

I try to remake this sample and I done this including it to my app. Now I see, that listener and sender is create properly and data was send, but I didn't get this send data returing to the listener. I don't know, what is wrong with it. This is my code:


void gameMenu::CreateUDPListener(Platform::String^ port)
{
    
    listener = ref new DatagramSocket();
    listenerContext = ref new ListenerContextUDP(listener);
    listener->MessageReceived += ref new TypedEventHandler<DatagramSocket^, DatagramSocketMessageReceivedEventArgs^>(listenerContext, &ListenerContextUDP::OnMessage);
    create_task(listener->BindServiceNameAsync(port)).then([this](task<void> previousTask)
    {
        try
        {
            FW1_RECTF rect;
            // Try getting an exception.
            previousTask.get();
            rect = { 50.0f, 200.0f, 2500.0f, 200.0f };
            fontWrapper->AnalyzeString(NULL, L"listener!", L"Segoe UI", 0.0146f*width, &rect, 0xffffffff, FW1_NOFLUSH, textMainGeometry);
        }
        catch (Exception^ exception)
        {
            FW1_RECTF rect;
            rect = { 50.0f, 350.0f, 2500.0f, 350.0f };
            fontWrapper->AnalyzeString(NULL, L"error 1", L"Segoe UI", 0.0146f*width, &rect, 0xffffffff, FW1_NOFLUSH, textMainGeometry);
        }
    });
}

void gameMenu::CreateUDPSender(Windows::Networking::HostName^ hostName, Platform::String^ port)
{
    socket = ref new DatagramSocket();
    SocketContextUDP^ socketContextInside = ref new SocketContextUDP(socket, devRes);
    socket->MessageReceived += ref new TypedEventHandler<DatagramSocket^, DatagramSocketMessageReceivedEventArgs^>(socketContextInside, &SocketContextUDP::OnMessage);
    create_task(socket->ConnectAsync(hostName, port)).then([this, socketContextInside](task<void> previousTask)
    {
        try
        {
            // Try getting an exception.
            previousTask.get();
            socketContextInside->SetConnected();
            socketContext = socketContextInside;
            FW1_RECTF rect;
            rect = { 50.0f, 250.0f, 2500.0f, 250.0f };
            fontWrapper->AnalyzeString(NULL, L"sender!", L"Segoe UI", 0.0146f*width, &rect, 0xffffffff, FW1_NOFLUSH, textMainGeometry);
        }
        catch (Exception^ exception)
        {
            FW1_RECTF rect;
            rect = { 50.0f, 350.0f, 2500.0f, 350.0f };
            fontWrapper->AnalyzeString(NULL, L"error 2", L"Segoe UI", 0.0146f*width, &rect, 0xffffffff, FW1_NOFLUSH, textMainGeometry);
        }
    });
}

void gameMenu::SendDataOverUDP(String^ data)
{
    if (!socketContext->IsConnected())
    {
        FW1_RECTF rect;
        rect = { 50.0f, 300.0f, 2500.0f, 300.0f };
        fontWrapper->AnalyzeString(NULL, L"no sender", L"Segoe UI", 0.0146f*width, &rect, 0xffffffff, FW1_NOFLUSH, textMainGeometry);
        return;
    }
    create_task(socketContext->GetWriter()->StoreAsync()).then(
        [this, data](task<unsigned int> writeTask)
    {
        try
        {
            // Try getting an excpetion.
            writeTask.get();
            FW1_RECTF rect;
            rect = { 50.0f, 300.0f, 2500.0f, 300.0f };
            fontWrapper->AnalyzeString(NULL, L"data send!", L"Segoe UI", 0.0146f*width, &rect, 0xffffffff, FW1_NOFLUSH, textMainGeometry);
            //SendOutput->Text = "\"" + stringToSend + "\" sent successfully";
        }
        catch (Exception^ exception)
        {
            FW1_RECTF rect;
            rect = { 50.0f, 350.0f, 2500.0f, 350.0f };
            fontWrapper->AnalyzeString(NULL, L"error 3", L"Segoe UI", 0.0146f*width, &rect, 0xffffffff, FW1_NOFLUSH, textMainGeometry);
        }
    });
}

SocketContextUDP::SocketContextUDP(DatagramSocket^ socket, const std::shared_ptr<DX::DeviceResources>& deviceResources) :
devRes(deviceResources)
{
    this->socket = socket;
    this->connected = false;
}

SocketContextUDP::~SocketContextUDP()
{
    // The socket (data writer) can be closed in two ways:
    //  - explicit: by using delete operator (the socket or the stream used by data writer is closed even if there
    //    are outstanding references to the objects).
    //  - implicit: by removing last reference to it (i.e. falling out-of-scope).
    // In this case this is the last reference to the socket and data writer so both will yield the same result.
    delete socket;
    socket = nullptr;

    if (writer != nullptr)
    {
        delete writer;
        writer = nullptr;
    }
}

void SocketContextUDP::OnMessage(DatagramSocket^ socket, DatagramSocketMessageReceivedEventArgs^ eventArguments)
{
    try
    {
        unsigned int stringLength = eventArguments->GetDataReader()->UnconsumedBufferLength;
        FW1_RECTF rect;
        rect = { 50.0f, 400.0f, 2500.0f, 400.0f };
        menu->GetWrapper()->AnalyzeString(NULL, L"receive data", L"Segoe UI", 0.0146f*1920.0f, &rect, 0xffffffff, FW1_NOFLUSH, menu->GetMainGeometry());
        //NotifyUserFromAsyncThread("Receive data from remote peer: \"" + eventArguments->GetDataReader()->ReadString(stringLength) + "\"",NotifyType::StatusMessage);
    }
    catch (Exception^ exception)
    {
        SocketErrorStatus socketError = SocketError::GetStatus(exception->HResult);
        if (socketError == SocketErrorStatus::ConnectionResetByPeer)
        {
            FW1_RECTF rect;
            rect = { 50.0f, 400.0f, 2500.0f, 400.0f };
            menu->GetWrapper()->AnalyzeString(NULL, L"err1", L"Segoe UI", 0.0146f*1920.0f, &rect, 0xffffffff, FW1_NOFLUSH, menu->GetMainGeometry());
        }
        else if (socketError != SocketErrorStatus::Unknown)
        {
            FW1_RECTF rect;
            rect = { 50.0f, 400.0f, 2500.0f, 400.0f };
            menu->GetWrapper()->AnalyzeString(NULL, L"err2", L"Segoe UI", 0.0146f*1920.0f, &rect, 0xffffffff, FW1_NOFLUSH, menu->GetMainGeometry());
        }
        else
        {
            FW1_RECTF rect;
            rect = { 50.0f, 400.0f, 2500.0f, 400.0f };
            menu->GetWrapper()->AnalyzeString(NULL, L"err3", L"Segoe UI", 0.0146f*1920.0f, &rect, 0xffffffff, FW1_NOFLUSH, menu->GetMainGeometry());
            throw;
        }
    }
}

DataWriter^ SocketContextUDP::GetWriter()
{
    if (writer == nullptr)
    {
        writer = ref new DataWriter(socket->OutputStream);
    }

    return writer;
}

boolean SocketContextUDP::IsConnected()
{
    return connected;
}

void SocketContextUDP::SetConnected()
{
    connected = true;
}

void ListenerContextUDP::OnMessage(DatagramSocket^ socket, DatagramSocketMessageReceivedEventArgs^ eventArguments)
{
    if (outputStream != nullptr)
    {
        EchoMessage(eventArguments);
        return;
    }

    // We do not have an output stream yet so create one.
    create_task(socket->GetOutputStreamAsync(eventArguments->RemoteAddress, eventArguments->RemotePort)).then(
        [this, socket, eventArguments](IOutputStream^ stream)
    {
        // It might happen that the OnMessage was invoked more than once before the GetOutputStreamAsync completed.
        // In this case we will end up with multiple streams - make sure we have just one of it.
        EnterCriticalSection(&lock);

        if (outputStream == nullptr)
        {
            outputStream = stream;
            hostName = eventArguments->RemoteAddress;
            port = eventArguments->RemotePort;
        }

        LeaveCriticalSection(&lock);

        EchoMessage(eventArguments);
    }).then([this, socket, eventArguments](task<void> previousTask)
    {
        try
        {
            // Try getting all exceptions from the continuation chain above this point.
            previousTask.get();
        }
        catch (Exception^ exception)
        {
            //NotifyUserFromAsyncThread("Getting an output stream failed with error: " + exception->Message,NotifyType::ErrorMessage);
        }
    });
}

ListenerContextUDP::ListenerContextUDP(DatagramSocket^ listener)
{
    this->listener = listener;
    InitializeCriticalSectionEx(&lock, 0, 0);
}

ListenerContextUDP::~ListenerContextUDP()
{
    // The listener can be closed in two ways:
    //  - explicit: by using delete operator (the listener is closed even if there are outstanding references to it).
    //  - implicit: by removing last reference to it (i.e. falling out-of-scope).
    // In this case this is the last reference to the listener so both will yield the same result.
    delete listener;
    listener = nullptr;

    DeleteCriticalSection(&lock);
}

void ListenerContextUDP::EchoMessage(DatagramSocketMessageReceivedEventArgs^ eventArguments)
{
    if (!IsMatching(eventArguments->RemoteAddress, eventArguments->RemotePort))
    {
        // In the sample we are communicating with just one peer. To communicate with multiple peers application
        // should cache output streams (i.e. by using a hash map), because creating an output stream for each
        // received datagram is costly. Keep in mind though, that every cache requires logic to remove old
        // or unused elements; otherwise cache turns into a memory leaking structure.
        //NotifyUserFromAsyncThread("Got datagram from " + eventArguments->RemoteAddress->DisplayName + ":" +eventArguments->RemotePort + ", but already 'connected' to " + hostName->DisplayName + ":" +port, NotifyType::ErrorMessage);
    }

    create_task(outputStream->WriteAsync(eventArguments->GetDataReader()->DetachBuffer())).then(
        [this](task<unsigned int> writeTask)
    {
        try
        {
            // Try getting an exception.
            writeTask.get();
        }
        catch (Exception^ exception)
        {
            //NotifyUserFromAsyncThread("Echoing a message failed with error: " + exception->Message,NotifyType::ErrorMessage);
        }
    });
}

bool ListenerContextUDP::IsMatching(HostName^ hostName, String^ port)
{
    return (this->hostName == hostName && this->port == port);
}

Edit for ankhd:

Boost.ASIO depends on the WinSock API, which just recently is now allowed on Windows Phone 8. However I'd bet that ASIO is using other APIs that are banned, that you'd have to replace.

No comment...

Advertisement

Did you notice, that this code is in C#?


The translation betweem C++/CLR and C# should be pretty simple, if you need to do it.
Also, Microsoft samples are often available in many languages if you look -- I don't know about this one in particular.

Finally, if you already tracked down that the packet makes it to the receiver, but the process doesn't get it, then what have you done to debug that problem?
Have you enabled broadcast on the receiver?
Are you binding to the right port?
What does Wireshark say on the receiving machine?
enum Bool { True, False, FileNotFound };

My code from previous post is port from this C# code to C++/CX and this code based on Microsoft sample. Did you see the previous linked datagram sample?

I use wireshark and I see, that isn't any data send to the network. Broadcast is enabled, port of receiver and sender is matching.

In the previoius message, you said that data was sent to the recipient, but it wasn't actually received by the receiving program.
In this latest message, you say that data isn't actually being sent from the sending program to the network.
Which one is it?

It's very hard to try to help you when you don't actually answer the questions we're asking to try to help you.

If you run the metronuggets code on sender and receiver, does it work?
enum Bool { True, False, FileNotFound };

I didn't know, that sender didn't send data to the network, because I think it does. I've checked it by wireshark and I discover this. I notice, that after send data, sender and receiver should activatet function OnMessage from my code, but it doesn't. I don't know why?

I cannot run metronuggest code, because my project isn't in c#.

Yea, come on! Give drawback. This forum is a group of imbecile, no one help, everybody can give minus points.... One of the most popular forums in this threat, you should shame of this!

I cannot run metronuggest code, because my project isn't in c#.


If you can't run that example to compare with, then you can't figure out whether the problem is your networking hardware, your computer/OS, or your own code, or something else.

I think this forum has exhausted its ability to read your mind, and its ability to help you when you don't actually try all the things suggested, and don't actually answer all the questions asked. If you want someone to write your code for you and/or lead you to the solution in person, I suggest hiring a contractor.
enum Bool { True, False, FileNotFound };

I'm completly out... DatagramSample runs very well, so why I should run metronuggest code? Can you exaplain for me, because it's really interesting.

Does the datagram sample run well with broadcast?
enum Bool { True, False, FileNotFound };

I don't know. I try to rewrite this metronuggest code to c++ and I get this:

listener = ref new DatagramSocket();
    listenerContext = ref new ListenerContextUDP(listener);
    listener->MessageReceived += ref new TypedEventHandler<DatagramSocket^, DatagramSocketMessageReceivedEventArgs^>(listenerContext, &ListenerContextUDP::OnMessage);
    create_task(listener->BindServiceNameAsync("22345")).then([this](task<void> previousTask)
    {
        HostName^ MyHostName = ref new HostName("192.168.0.11");
//        listener->JoinMulticastGroup(MyHostName);

        task<IOutputStream^>(listener->GetOutputStreamAsync(MyHostName, "22345")).then([this](IOutputStream^ stream)
        {

            String^ stringToSend("Hello");
            DataWriter^ writer = ref new DataWriter(stream);
            writer->WriteString(stringToSend);
            create_task(writer->StoreAsync()).then([this](task<unsigned int> writeTask)
            {
                try
                {
                    FW1_RECTF rect;
                    rect = { 50.0f, 300.0f, 2500.0f, 300.0f };
                    fontWrapper->AnalyzeString(NULL, L"data send!", L"Segoe UI", 0.0146f*width, &rect, 0xffffffff, FW1_NOFLUSH, textMainGeometry);
                    writeTask.get();
                }
                catch (Exception^ exception)
                {
                    if (SocketError::GetStatus(exception->HResult) == SocketErrorStatus::Unknown)
                    {
                        throw;
                    }

                }
            });
        });
    });

I think, that it is similar to this in C#, but is doesn't work, anybody know, why?(in wireshark I didn't see any packets in network)

This topic is closed to new replies.

Advertisement