DatagramSocket in Juce (beginer)


#1

Hi,

I’m new to socket programming, and trying to connect a Nintendo DS to my Juce app via Wifi (UDP). I have no clue where to initialize the connection. For now I’m giving my MainComponent members DatagramSocket socket and int bytes, and at the end of the app constructor, i’m doing this :

socket.bindToPort(54000);
socket.waitUntilReady(true,-1);
    
while(true)
{
    socket.read(&bytes, 128, false);
}

I’m pretty sure it is ridiculously false (the app is not running), but I didn’t find any tutorial on this topic…
For now I’m trying to send datas using PuTTY.
If someone could help me with the basics, or send me to a website that could explain those concepts, it would be really apreciated !

Best regards,

Thibault


#2

Your code is close enough, but JUCE applications are ‘event driven’, so you need to have your read loop run on a separate thread, so as not to block the event loop (aka message manager). I just looked at some code of mine and it looks like I call waitUntilReady before every read, but I don’t know if that is needed or not.


#3

Thank you for the reply !
Could it be possible to post a basic example ? I have no clue how to run a separate thread… Is it something like the loop starts when a button is pressed ?
Thanks in advance !


#4

I wish I had some simple example code for you, but all of my code is wrapped up in the specifics of the task… There are several JUCE ways to do threading, and I tend to use the Thread class. There is a threading example in the JUCE examples, MultithreadingDemo.h. The most important thing to understand is sharing data between threads, using data guards like CriticalSections or atomic values, so that you don’t try to read a piece of data in one thread, while the other one is writing to it.


#5

Ok I’ve created a separated thread to run my read loop. Now my problem is that the socket won’t be ready to read. The waitUntilReady function returns 0. The weird part is that I can connect my app to write, as waitUntilReady(false, -1) returns 1, but never to read. I’ve tried to shut down my firewall, nothing changes.

Here is my code :

ScopedPointer<DatagramSocket> socket;

socket = new DatagramSocket;

if(socket->bindToPort(8888))
    ready("bound");
else
    ready("not bound");

connection("connection...");
int i = socket->waitUntilReady(true, 5000);
if(i == -1)
    connection("connection : error");
else if(i == 0)
    connection("not connected");
else
    connection("connected !");

while(!threadShouldExit())
{
    wait (10);
    
    const MessageManagerLock mmlock;
    if(!mmlock.lockWasGained())
        return;
        
    int r = socket->read(byt, 7, false);
        
    if(r > 0)
        update(byt);
    else if(r == 0)
        update("0");
    else
        update("error");
}   

ready(), connection() and update() are juste functions to print the corresponding message.

What could be the reason my app won’t accept to read ?


#6

I guess the reason is, that you didn’t call startThread by any chance?
Also I don’t see the reason for the MessageManagerLock at this place.
Third, you should prefer objects on the stack over ScopedPointers.

A rough untested example around your input could look like:

class MainComponent : public Component
{
public:
    MainComponent ()
    {
        readerThread.startThread();
    }

    virtual ~MainComponent ()
    {
        readerThread.stopThread();
    }

    void update (const String& foo)
    {
        // do your stuff
    }
private:
    class DatagramReader : public Thread
    {
    public:
        DatagramReader (MainComponent& ownerToUse) : 
            Thread ("Datagram Reader"),
            owner (ownerToUse) 
        {
            connect();
        }

        void run() override
        {
            while(!threadShouldExit())
            {
                auto ready = socket.waitUntilReady (true, 100);
                if (ready < 0)
                    // disconnected, do something here, maybe call `connect();`
                else if (ready == 0)
                    wait (1);
                else
                {
                    // from your example, I think you need to experiment here a bit
                    int r = socket.read (ready, 7, false); 

                    MessageManager::callAsync ([owner] {owner.update (r == 0 ? "0" : "error"); });
                }
            }
        }

    private:
        void connect ()
        {
            if(socket.bindToPort(8888))
                ready("bound");
            else
                ready("not bound");
        }

        MainComponent& owner;
        DatagramSocket socket;
    };
    DatagramReader readerThread { *this };
};

#7

Thank you for the advices, my code is clearly cleaner ! But my problem remains the same… Everyting works fine for writing, but if I want to read datas, the function waitUntilReady always returns 0… Where should I look ?


#8

I haven’t used the DatagramSocket in particular, but I would say, if it returns 0 that means, the other side is not sending anything?


#9

Oh, I see ! I tought waitUntilReady was only depending on the Juce part, before even looking if there was datas sent. So this function already check if datas are coming. That makes sense, thanks a lot !