C++ Interrupting UDP Listener. Compiled using oscpack in Xcode
Asked Answered
B

3

5

I have successfully incorporated an UDPreceive function into my application. HOWEVER! I can not figure out how to stop UDP listener from running infinitely. The OSCPack library has a Break() and AsynchronousBreak() built into it, but I have been unable to implement these.

in the udpSocket.cpp file within oscpack:

void Run() //the listener function (WORKING!)
{
    break_ = false; 
    //UDP Listener Code

    void Break()
    {
        break_ = true;
    }
    void AsynchronousBreak()
    {
        break_ = true;
        // Send a termination message to the asynchronous break pipe, so select() will return
        write( breakPipe_[1], "!", 1 );
    }
}

My attempt to call Break() from the packet Listener class doesn't appear to do anything, despite the compiler suggesting that everything is being called correctly:

SocketReceiveMultiplexer s;
s.Break();

Another method that I have tried was to raise an interrupt flag in accordance with the RunUntilSigInt() function. Within the packet listener class:

raise(SIGINT);

but this terminates the whole program, rather than just breaking from the UDPListener. For reference, here is the RunUntilSigInt() code within udpSocket.cpp:

void SocketReceiveMultiplexer::RunUntilSigInt()
{
    assert( multiplexerInstanceToAbortWithSigInt_ == 0 ); /* at present we support only one multiplexer instance running until sig int */
    multiplexerInstanceToAbortWithSigInt_ = this;
    signal( SIGINT, InterruptSignalHandler );
    impl_->Run();
    signal( SIGINT, SIG_DFL );
    multiplexerInstanceToAbortWithSigInt_ = 0;
}

I'm completely stuck on this one, any help/advice will be greatly appreciated.

Thanks, Tom

Bozuwa answered 19/9, 2014 at 15:45 Comment(2)
Send it a 'stop' datagram locally?Lancers
@MartinJames, thanks for that, something like this? #4671164Bozuwa
L
5

I know this is a somewhat old question, but I had to overcome this recently and didn't find a good answer online. The model used by oscpack seems to be that they control the infinite Run loop, and you implement everything you want to do inside a class derived from OscPacketListener. If you don't want to do things that way, you need to run the Run loop in a separate thread. It seems in the oscpack 1.1.0 release, there is no internal support for threading anymore. They explain in the CHANGES file for that release that you would need to implement your own threading solution. The Run routine in SocketReceiveMultiplexer never returns, so any code after that call is unreachable. The various Break routines are for controlling the execution of the Run loop from a different thread. In the below example I'm using c++11 <threads> but you can use any threading library you choose to accomplish something similar. In my example, you'll have to

#include <threads>
#include <mutex>

and compile your code with a c++11 compatible compiler. In g++ you would need the -std=c++11 command line argument.

If you start with the receiver example (parsing single messages example) in the SVN, you could change the main() function to be something like

void ListnerThread()
{
    PacketListener listener;
    UdpListeningReceiveSocket s(
            IpEndpointName( IpEndpointName::ANY_ADDRESS, PORT ),
            &listener );
    s.Run();
}

Somewhere else in your code, make a call like

std::thread lt(ListnerThread);

in order to start the listener running. You'll have to create some means of sharing information between your main thread and the listener thread. One simple method is to use a global variable surrounded by a mutex (also global). There are certainly other (better?) ways but this is very easy. Declare these globally (following their example) instead of within the ProcessMessage function:

std::mutex oscMutex;

bool a1;
osc::int32 a2;
float a3;
const char *a4;

Inside the ExamplePacketListener, where they set the variables from the args stream and then make a call to cout you would do something like

oscMutex.lock();
args >> a1 >> a2 >> a3 >> a4 >> osc::EndMessage;
oscMutex.unlock();

Just be sure to also lock() and unlock() the mutex in the same way wherever you access those variables elsewhere in your code.

Lyceum answered 5/12, 2014 at 10:12 Comment(2)
Matth, thanks for the pointers! I figured it needed to be run in a different thread, but couldn't manage to implement this in iOS. I'll be working on this project again in 2015, so I'll have time to try out your method. Cheers, Tom.Bozuwa
Hi there. Since I have my own main loop, is there another way to incorporate the osc::UdpSocket::ReceiveFrom() in my main loop?Limitation
H
2

This is old, but this is the only page on the web about this issue. In case someone needs oit

Using raise(SIGINT) when i run the listener with RunUntilSigInt() function does the trick for me. It's a quick hack and it is ugly but it goes like this:

        if (std::strcmp(m.AddressPattern(), "/test1") == 0) {

            osc::ReceivedMessageArgumentStream args = m.ArgumentStream();

            osc::int32 a1, a2, a3;
            const char *a4;
            args >> a1 >> a2 >> a3 >> a4 >> osc::EndMessage;

            raise(SIGINT);
        }

In this case, i stop the listener when i receive one pack, but you can modify it as you wish.

Hogg answered 19/12, 2015 at 21:17 Comment(0)
S
0

Sorry for stupid question: did you try to run the listener before the breaking?

SocketReceiveMultiplexer s;
s.Run(); // let wire up the things
s.Break();
Saprophagous answered 19/9, 2014 at 16:1 Comment(1)
Hi Yuri, Yes, the listener is Run() from my main program. As I mentioned above, the code is running perfectly... apart from the fact I can't break from the listener and resume with other tasks!!! Thanks, Tom.Bozuwa

© 2022 - 2024 — McMap. All rights reserved.