Finding and Reserving Open Ports for QUdpSocket

Started by
8 comments, last by Slavik81 13 years, 1 month ago
I'm having a little trouble figuring out how to create UDP sockets on open ports. I'll be running multiple instances of my application on the same computer at the same time, and so it cannot use hardcoded ports. Communication is 2-way, so I need two ports. One port for Component 1 and one port for Component 2. Both components are part of the same process, but are in different threads.

The problem is choosing the ports. As far as I know, you cannot find and reserve a free port without binding to it. So I bind 2 ports. Now I know what ports I can use. Both components need to know both ports in order to send and receive, though they only each really need to bind to the one they receive on. Unfortunately, after the first component binds 2 sockets and tells the second component what ports to use, the second component can't bind to the port it needs (since the first Component is still bound to it).

The preferred solution would be for Component 1 to be able to be able to reserve an open port for Component 2. Perhaps by binding but allowing a second socket on the same port to be bound. Or throwing the socket object across the thread boundary somehow.

I would love if this code printed "Success". (Using Qt 4.5)
void theProblem()
{
QHostAddress udpHost("localhost");
quint16 port = 0;

QUdpSocket socket;
socket.bind(udpHost, port);

createSocketInNewThread(udpHost, socket.localPort());
sendMessageToSocketInNewThread(udpHost, socket.localPort());
}

void createSocketInNewThread(const QHostAddress& udpHost, int port)
{
// Pretend we're in a new thread.
QUdpSocket secondSocket;
bool successfullyBound = secondSocket.bind(udpHost, port);
qDebug("%s", successfullyBound?"Success":"Failure");
}
Advertisement
Both components need to know both ports in order to send and receive, though they only each really need to bind to the one they receive on. Unfortunately, after the first component binds 2 sockets and tells the second component what ports to use, the second component can't bind to the port it needs (since the first Component is still bound to it).[/quote]
To have two things talking to each other, each needs its own socket with its own address(localhost):port pair.

So each thread creates one socket and lets anyone else know which port it's connected to.

Both components need to know both ports in order to send and receive, though they only each really need to bind to the one they receive on. Unfortunately, after the first component binds 2 sockets and tells the second component what ports to use, the second component can't bind to the port it needs (since the first Component is still bound to it).

To have two things talking to each other, each needs its own socket with its own address(localhost):port pair.

So each thread creates one socket and lets anyone else know which port it's connected to.
[/quote]
I'd prefer to have it fixed prior to their creation. What you're suggesting is to half-initialize Component 1 choosing one port, then initialize Component 2 choosing the second port, and then go back to finish construction of Component 1 using the second port that was chosen. If possible, I'd rather choose a pair of unused ports, construct Component 1, then construct Component 2.

That's easy with Component 1 just by passing in the socket itself, but Component 2 runs in a different thread, and so I think I need to construct it inside the thread and just pass in the information required for construction. Or it's impossible and I need a completely different, more annoying approach.

The problem is choosing the ports. As far as I know, you cannot find and reserve a free port without binding to it. So I bind 2 ports. Now I know what ports I can use. Both components need to know both ports in order to send and receive, though they only each really need to bind to the one they receive on. Unfortunately, after the first component binds 2 sockets and tells the second component what ports to use, the second component can't bind to the port it needs (since the first Component is still bound to it).
Binding ports to sockets doesn't work that way. You won't be able to bind and query reliably because there is no atomic operation. Some other program on your computer, or another instance of your application, could bind the port behind your back.

I'm also wondering if you're forgetting that a connection contains both the source AND destination information. A single incoming IP+port pair can support about 2^48 connections to it, one for each other IP+port pair out there.

You might be able to attempt to bind, and if it fails, attempt to bind on a subsequent port. For example, attempt to bind on port N, and on failure, attempt to bind on port N+1, repeating until you exhaust your pool.

What are you attempting to accomplish with this? Perhaps we can give better help if you explain the problem, not just your attempted solution to the problem.

The only think I can think of is that you are trying to implement something along the lines of NAT punch-through on a local machine, but that'sthe wrong approach for that.

I'd prefer to have it fixed prior to their creation. What you're suggesting is to half-initialize Component 1 choosing one port, then initialize Component 2 choosing the second port, and then go back to finish construction of Component 1 using the second port that was chosen. If possible, I'd rather choose a pair of unused ports, construct Component 1, then construct Component 2.



There is no such thing as a "half-initialized" socket here.You (almost) never use connect() with an UDP socket.
Simply pass the address:port of component 2 to the call to sendto() when you send from component 1.
enum Bool { True, False, FileNotFound };

There is no such thing as a "half-initialized" socket here.You (almost) never use connect() with an UDP socket.
Simply pass the address:port of component 2 to the call to sendto() when you send from component 1.

I'm not familiar with the POSIX(?) terms you're using, but I didn't mean that the socket would be half initialized. I'm using 3rd-party library code, and the constructor requires a bound socket to read from, and a hostaddress + port to write to. Component 1 and Component 2 each have one of these objects, allowing them to read and write to each other. The object is essentially is one half of a connection built on top of UDP. Thus, you need to know both ports before you can create this object. If the second port is not determined until Component 2 is initialized, Component 1 cannot not fully initialize prior to Component 2's construction.

I believe I do have a solution, though. According to StackOverflow, I was wrong about being unable to pass QUdpSocket across threads. It seems I can create and bind my two sockets prior to constructing either component, and just pass them into the constructors of my components. Component 1 is easy, but for Component 2 I I have to shuffle it over the thread boundary before use (presumably with QObject::moveToThread). I'm still in the process of trying that... there's a decent amount of code to change to do that dependency injection.

My StackOverflow question might have been clearer. You guys helped me understand my question better, so I think I phrased it more clearly over there:
http://stackoverflow...ifferent-thread

I believe I do have a solution, though. According to StackOverflow, I was wrong about being unable to pass QUdpSocket across threads. It seems I can create and bind my two sockets prior to constructing either component, and just pass them into the constructors of my components. Component 1 is easy, but for Component 2 I I have to shuffle it over the thread boundary before use (presumably with QObject::moveToThread). I'm still in the process of trying that... there's a decent amount of code to change to do that dependency injection.


These problems are all over the place...

struct CommunicationPair {
QUdpSocket * a;
QUdpSocket * b;
};

struct Component {
QUdpSocket mySocket;
};

{
Component * ca = new Component();
Component * cb = new Component();

CommunicationPair * cp = new CommunicationPair(&ca->mySocket, &cb->mySocket);

ca->communicateVia(cp);
cb->communicateVia(cp);
}


Sockets are thread-safe technically, but not conceptually. If two threads call recv() on same socket, depending on what is being transferred, the packet one receives might not be intended or might be out-of-order.

But at least as far as underlying network stack goes, there is nothing wrong with passing sockets across threads. It's not like OGL or some windowing APIs which have strict rules on who calls what and when.

there's a decent amount of code to change to do that dependency injection.[/quote]But, but, but... DI makes it easy to refactor... It decouples things.... :P
Why are you using UDP for local inter-thread communication? What is your high level goal here?

These problems are all over the place...

struct CommunicationPair {
QUdpSocket * a;
QUdpSocket * b;
}
Component * ca = new Component();
Component * cb = new Component();

CommunicationPair * cp = new CommunicationPair(&ca->mySocket, &cb->mySocket);

ca->communicateVia(cp);
cb->communicateVia(cp);
}
...


Sockets are thread-safe technically, but not conceptually. If two threads call recv() on same socket, depending on what is being transferred, the packet one receives might not be intended or might be out-of-order.

But at least as far as underlying network stack goes, there is nothing wrong with passing sockets across threads. It's not like OGL or some windowing APIs which have strict rules on who calls what and when.

there's a decent amount of code to change to do that dependency injection.
But, but, but... DI makes it easy to refactor... It decouples things.... :P
[/quote]


That's close to what I was thinking of. But only one bound socket is used for each component. They don't need or want to touch the remote socket instance. There's an imaginary program boundary between the two objects. They cannot be allowed to directly interact. I'm thinking something more like:

{
QUdpSocket* readSocketA = createSocketBoundToAnyPort();
QUdpSocket* readSocketB = createSocketBoundToAnyPort();

Component1 a(readSocketA, readSocketB.localAddress(), readSocketB.localPort());
Component2 b(readSocketB, readSocketA.localAddress(), readSocketA.localPort());
}


Somewhere in Component2's constructor, it starts a new thread, and moves the socket into that thread.
Nothing besides Component1 will ever touch readSocketA. Nothing besides Component2 will ever touch readSocketB. I think in this instance, that means it's ok.

Dependency injection is great, but Component2 is a huge chunk of untested, legacy code that I'm stuck with, and it doesn't use DI. The less I touch it, the better. All the new stuff I do is based on dependency injection.


Why are you using UDP for local inter-thread communication? What is your high level goal here?

The two components are nearly entire programs. They are comprised of just about everything except the GUI for 2 separate programs that will run on different machines, though some of their dependencies have been replaced with fakes (like settings readers and such). I'm instantiating them in my test in order to ensure that data will flow correctly through the entire system. I have a single test server and multiple people will likely be executing this test at the same time. The problem I was having was that the tests would sometimes fail because another instance of the test was running. I'm now seeing some other options, but I think the dependency injection is working out for me thus far...

Having both components in the same process is not quite representative of the final system, but for now it should make for a decent testing playground. The actual setup of the test is isolated from the test cases, so one day if I do get around to adding the RPC framework and such necessary for a multi-process test, I could do it. If I ever do get to that (and that's a big if), I might have to revisit this.
Well, everything's done now and it worked perfectly. Ultimately, it looked vaguely like this, though I'm leaving a few things out and rearranging a couple things in this simplified version.
[color="#1C2837"][font="CourierNew, monospace"] [/font]
[color="#1C2837"][font="CourierNew, monospace"] [/font]{
QUdpSocket* readSocketA = createSocketBoundToAnyPort();
QUdpSocket* readSocketB = createSocketBoundToAnyPort();

Component1 a(readSocketA, readSocketB.localAddress(), readSocketB.localPort());
Component2 b(readSocketB, readSocketA.localAddress(), readSocketA.localPort());
b.start();
}

/* Component 2 inherits from QThread
*/
Component2::Component2(QUdpSocket* boundReadSocket, QHostAddress writeAddress, int writePort)
{
boundReadSocket->readAll(); // discard any data it came with
boundReadSocket->moveToThread(this);
}


EDIT: This post editor isn't quite WYSIWYG.

This topic is closed to new replies.

Advertisement