Using Datagram Socket waitForNextConnection method


#1

Hi!

I’ve been getting up to speed with juce recently, and have been loving it so far. Inevitably however my learning has taken me to a point where I’ve my first question for this forum :slight_smile:

I’ve been looking at the example code in the “Juce Demo” for using sockets in interprocess connections, trying to adapt the code to work with the DatagramSocket class (UDP) instead of StreamingSocket as in the example.

My efforts have taken me to the point were sending a packet to my program results in the waitForNextConnection() method being called, however in that method the block:

if (recvfrom (handle, buf, 0, 0, &address, &len) > 0) { return new DatagramSocket (inet_ntoa (((struct sockaddr_in*) &address)->sin_addr), ntohs (((struct sockaddr_in*) &address)->sin_port), -1, -1); }

Is never entered!

The same happens when I just run a minimal juce program where the code:

ScopedPointer <DatagramSocket> socket = new DatagramSocket(6666); DatagramSocket* sock = socket->waitForNextConnection();

is at the end of the constructor. The waitForNextConnection() method never returns neither data or ‘0’. I am certain however in both cases that it is reached, as breakpoints placed within it are reached when the program receives a packet.

In case it matters, I’m using visual studio on Win 7.

Am I using the DatagramSocket wrong? Perhaps I shouldn’t be using the waitForNextConnection() method at all?

To give some context, I’m developing a platform-independent app that needs to send and receive OSC messages.

Any tips on how to get working with the DatagramSocket class would be greatly appreciated!

Thanks :slight_smile:


#2

You can’t wait for a connection on a UDP aka Datagram socket (datagram is connectionless).
You can wait for the socket to become read-able and then read some data out of it.


#3

Hi, thank you for your reply!

I knew indeed that, unlike TCP, UDP is connectionless.

The only reason that I nonetheless thought that using the WaitForNextConnection() method was the way to go, despite the word “Connection” in the name, was the instruction in the DatagramSocket classes’ constructor comment/documentation:

//==============================================================================
/**
Creates an (uninitialised) datagram socket.

    The localPortNumber is the port on which to bind this socket. If this value is 0,
    the port number is assigned by the operating system.

    To use the socket for sending, call the connect() method. This will not immediately
    make a connection, but will save the destination you've provided. After this, you can
    call read() or write().

    If enableBroadcasting is true, the socket will be allowed to send broadcast messages
    (may require extra privileges on linux)

    To wait for other sockets to connect to this one, call waitForNextConnection().
*/

I will disregard my erroneous interpretation of the last instruction there then and just use the waitUntilReady() method in my packet-receiving-thread…

Just out of curiosity, since we know UDP is connectionless, what purpose does a waitForNextConnection() method serve?

Thanks!


#4

Actually, scrap that, I found a post of yours from a few years back where you mention this. (http://www.rawmaterialsoftware.com/viewtopic.php?f=2&t=2285)

Fair enough then, I can work without waitFornextConnection as well!

Thank you!


#5

…And unscrap it :slight_smile:

I’ve spent a few hours trying to figure this out, but my background in Java C# etc doesn’t seem to be of much help here…

I’ve only managed to find one example of how this is done: http://www.rawmaterialsoftware.com/viewtopic.php?f=2&t=7230

However I think this example is wrong.

while( ! threadShouldExit() ) { unsigned char us8DestBuffer; int iReadyForReading = _pDatagramSocket->waitUntilReady( false , 1000 ); int iMaxBytesRead = _pDatagramSocket->read( ( unsigned char* ) &us8DestBuffer , 1 , true ); }

I send an OSC text string over UDP from a java program. From my understanding of the above code, only the first character is read, and there doesn’t seem to be any knowledge anywhere of how long the received message is.

Would it be easy for someone to post a very simple example of how to properly receive a text string over UDP to get me started?

Thanks!


#6

I don’t understand your last post.
read returns the amount of data read. (And since the maximum size of a UDP packet is 65535 bytes, you can preallocate such a buffer).
Basically, in your example, you can add a “if (iMaxBytesRead > 0) { doSomethingWithBuffer(); }” on the last line

I would not use a 1 char buffer anyway, since it’s utterly slow (think about it, for one byte, you have to switch to kernel space then the kernel has to perform a O(log N) search in all received packet to figure the one for you, then copy a single byte (and likely not discard the message) to the user-space buffer, and finally switch back to your process/thread where you’ll likely concatenate this byte in a bigger buffer anyway).


#7

Oh, and by the way, if you send a 543 bytes buffer on one side, you’ll read 543 bytes on the other side, unless you tell the system to aggregate the packets (which is not the default for UDP), and provided your receiving buffer is large enough to store such message.


#8

Dear X-Ryl669 :slight_smile:

Thank you!

That did indeed put a few things in the right order in my mind. I’ll proceed with finishing what I was trying to do, and will then post back the code that works for me, in case it makes this thread worth reading for whomever stumbles upon it again in the future…


#9

Just for this thread to be somewhat useful to readers of the forum, here’s what worked for me.

The main program here is based on the main program in the juced tutorial, however I’ve omitted the code for the TextConsole component for the sake of brevity. It’s an on-screen text component that you can post text strings to, so nothing worth posting here, you can see it in the juced tutorial.

To the best of my understanding the code below is the minimum necessary to start a thread listening for UDP packets, and to communicate properly between the listener thread and the main application thread.

[code]#ifndef JUCER_HEADER_MAINCOMPONENT_MAINCOMPONENT_D0F6CD31
#define JUCER_HEADER_MAINCOMPONENT_MAINCOMPONENT_D0F6CD31

#include “…/Juce Library Code/JuceHeader.h”
#include “TextConsole.h”
#include “OSC\OSC_Listener.h”

class MainComponent : public Component
{
public:
MainComponent();
~MainComponent();

void resized();

void appendMessage (const String& message);

juce_UseDebuggingNewOperator

private:

OSC_Listener* m_OSCListener;

TextConsole* console;

// (prevent copy constructor and operator= being generated..)
MainComponent (const MainComponent&);
MainComponent& operator= (const MainComponent&);

};

#endif // JUCER_HEADER_MAINCOMPONENT_MAINCOMPONENT_D0F6CD31
[/code]

[code]#include “MainComponent.h”

MainComponent::MainComponent()
{
console = new TextConsole();

addAndMakeVisible(console);

setSize (580, 800);

m_OSCListener = new OSC_Listener(*this, 6666);

m_OSCListener->startThread();

}

void MainComponent::appendMessage(const String& message)
{
console->addLine(message);
}

MainComponent::~MainComponent()
{
delete m_OSCListener;

deleteAllChildren();

}

//==============================================================================

void MainComponent::resized()
{
console->setBounds (10, getHeight() - 500, getWidth() - 20, 490);
}
[/code]

[code]#ifndef OSC_LISTENER_H
#define OSC_LISTENER_H

#include “…/…/Juce Library Code/JuceHeader.h”

class MainComponent;

class OSC_Listener: public Thread, private MessageListener
{
public:
OSC_Listener::OSC_Listener(MainComponent& owner_, int port);

~OSC_Listener();

void handleMessage (const Message& message);
   
void run();

protected:

private:
int m_Port;

ScopedPointer <MemoryBlock>		messageData;
ScopedPointer <DatagramSocket>	socket;

MainComponent& owner;

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSC_Listener);

};

#endif[/code]

[code]#include “OSC_Listener.h”
#include “…/MainComponent.h”

OSC_Listener::OSC_Listener(MainComponent& owner_, int port) : Thread (“OSC_Listener Thread”), owner (owner_), m_Port(port)
{

}

OSC_Listener::~OSC_Listener()
{
signalThreadShouldExit();

if (socket != 0)
	socket->close();

// allow the thread 2 seconds to stop cleanly - should be plenty of time.
stopThread (2000);

}

void OSC_Listener::handleMessage (const Message& message)
{
if(message.intParameter1 == 1) // 1 means I’ve received stuff.
{
int length = message.intParameter2;

	ScopedPointer <MemoryBlock> data (static_cast <MemoryBlock*> (message.pointerParameter));

// Here you can do whatever you see fit to the packet received.
// ProcessPacket(…);

// And here, just to demonstrate how this thread can then talk back to the thread where it was started, I create a String which could otherwise also have been derived from the received packet content…
String toPrint(“Here you can put the message you got”);

	owner.appendMessage(toPrint);
}

}

void OSC_Listener::run()
{
messageData = new MemoryBlock(65535, true);
socket = new DatagramSocket(m_Port);

int readyForReading;
int bytesRead;

// threadShouldExit() returns true when the stopThread() method has been
// called, so we should check it often, and exit as soon as it gets flagged.
while (! threadShouldExit())
{

	// What should I have as a timeout value here? -1 seems to work, but then "threadShouldExit()" is never checked. 1000 is probably a better choice.
	readyForReading	= socket->waitUntilReady( true , 1000 );

	if(readyForReading>0)
	{
		bytesRead = socket->read(static_cast <char*> (messageData->getData()), 65535, false );     

		postMessage(new Message(1, bytesRead, 0, new MemoryBlock(*messageData)));
	}
}

}
[/code]


#10
  • forum software double posted this - sorry -

#11

Hello!

This thread is rather old, but my question is very much related to this, so i decided to ask here instead of opening a new topic with the same name and question…

I’m also trying to read data from a DatagramSocket, and I use a Thread for polling. This thread polls for incoming data, but also polls for data to be send and passes that to the socket, if available.
This is my code: [code]void OSCSocket::OSCSocketThread::run()
{
char in_buffer[65535];
while (!threadShouldExit())
{
try {
// read data from udp socket, if possible

        int ready = m_parent->m_udp_socket->waitUntilReady(true,0);
        if (ready > 0)
        {
            // The socket is ready and has data for us to receive
            int read_res = m_parent->m_udp_socket->read(in_buffer, 65535, false);
            if (read_res > 0)
            {
                // It received data, now process it!
                m_parent->ProcessPacket(in_buffer, read_res);    
            }
            else if (read_res < 0)
            {
                // an error occurred
                Log::logLine("OSCSocketThread", "Error receiving data from host: '" + m_parent->m_remote_host_adress_string + ", port: " + String(m_parent->m_remote_port));
            }
        }
        
        // Now let's try to write something to the socket, if there's data available
        if (!m_data.empty())
        {
            ready = m_parent->m_udp_socket->waitUntilReady(false,0);
            if (ready == 1)
            {
            //the list with outgoing data is accessed from other threads to fill it. Therefore, a lock is required           
                {
                    const GenericScopedLock<SpinLock> a_lock (m_write_lock);
                    
                    data_struct d = m_data.front();
                    
                    m_parent->m_udp_socket->write(d.data, d.length);
                    m_data.pop_front();
                }
            }
        }
    }
    catch(...)
    {
        Log::logLine("OSCSocketThread", "exception occured!");
    }
}

}[/code]

Because reading and writing is both managed by this thread, I can’t afford to use waitUntilReady with a timeout. So I assumed that when i pass “0” as a timeout, it will return immediately.
I does indeed return immediately, but also the socket never gets readable, so I’m unsure, whether it is right to poll like that.
BTW: Writing works great!

Thanks in advance,
StrangeMan


#12

giving this thread a slight push


#13

Hello again,
After spending some time with other stuff, I came back to the problem I posted above. I still can’t see, whats wrong about it - am I just polling the wrong way or does the socket indeed never receive anything? My next guess was that “binding” the socket to a port is somewhat wrong.

Here is what I do to find a free port to bind the socket to:

[code]m_udp_socket = std::tr1::shared_ptr(new DatagramSocket(0, false));

// …

// lowest, undefined port
m_local_port = 100;
// try to bind to port, until a free port is found
while ((m_local_port<65535) && (!m_is_bound))
{
m_local_port++;
m_is_bound = m_udp_socket->bindToPort(m_local_port);
}[/code]

If I run that, the first free port it finds is this: 1024. And that is clear, because all port below are registered for other purposes.
Ok, so now the socket is bound to that port. But if I create another socket, and search for a free port for that, it will also find 1024! From my understanding of UDP, it is not possible to have to sockets listening to the same port, is it?

Is there something wrong about my code/results? Do you have any suggestions or hints for me?

Thanks so much,
StrangeMan

PS: I’m on the Mac. I tried to run a port-scan using “netstat -a” but I don’t really understand the output of it…


#14

Ports below 1024 are hard to access, on a Mac. You would need to run as root. Best to ignore them.

Ports can be re-used, yes, but it’s very awkward - incoming transmissions tend to just come to the first one, not be ‘routed’ in any way.

Why are you trying to bind like that? The main reason to bind is so that you’re on a known port - soanother connection can come to find you, in which case you can pick a specific number. I think for other cases there’s a way to bind to ‘any’ port - look for man pages on bind for UDP connections, it may be ‘0’.

Also see if Juce sets the REUSEADDR flag (something like that - find ‘reuse’)

Bruce