1

this is a test to create some temporary interprocess communication between applications using sockets. These applications will later be running on different systems , using a customized embedded communication system, but for now the latter is not available. As a result, I am looking for a quick - perhaps even slightly dirty - c++ way to implement interprocess communication between these applications. The applications will be sending some strings around (so nothing too fancy).

I stumbled upon oscpack which utilizes udp to implement message-passing for open sound control. I have compiled it in linux with gcc4.7.1 as a shared object using make lib. Note that I have to append option -fPIC in the COPTS variable in the Makefile.

With the shared library in place, I wrote a small proof of concept application, which uses a separate thread for the listening of messages, and in the main thread it waits for some string from stdin to forward it to the other application. I execute 2 very similar instances of this application. Its just that in the 2nd instance I have swapped the PORT_RCV and PORT_SND numbers.


Actual problem starts here:

The problem I face is that on the receiving end, when the call to osc::UdpSocket::ReceiveFrom() (which ultimately runs recvfrom()) unblocks, I get a return value of read bytes equal to zero (0). Also the char * data pointer is still pointing to zero. So in essence I have not received the string from the sender application, even though the recvfrom() unblocked at the right time.

From the manual pages I read that recv and recvfrom can return a value of 0 when the sender has closed the connection. But the sender in this case is using udp ie a connectionless ... connection :), so I am not sure if it applies here.

I have tried to use netcat to listen for udp messages in the corresponding port and verify that at least the sender part works. Indeed with netcat -u -l -p <sender port of the running instance> , I do receive the messages that I type in. So probably the problem is probably related to the receiver end.

The question is: am I using the recvfrom correctly?


please find attached the code to the interprocess communication test application (a full duplex messenger really). To execute 2 of them, first download and compile as library the oscpack library. Then copy the source below in two files and swap the PORT_RCV and PORT_SND numbers on the 2nd source file.

Then compile each with:

#compile
g++ -g -Wall -Wextra -pedantic -std=c++11  -I../oscpack -c -o "obj_dbg/messenger.opp" "src/messenger.cpp"

#link
g++ -g -Wall -Wextra -pedantic -std=c++11  -I../oscpack  obj_dbg/messenger.opp -o "messenger_dbg" -L../oscpack -pthread -loscpack

Then execute them and type a word, press enter and expect to (not) see it show up at the other application.

#include <iostream>
#include <string>
#include <string.h>

#include <thread>

#include <unistd.h>

#include "osc/OscReceivedElements.h"
#include "osc/OscPacketListener.h"
#include "ip/UdpSocket.h"

#include "osc/OscOutboundPacketStream.h"
#include "ip/UdpSocket.h"

using namespace std;
using namespace osc;

#define ADDRESS "127.0.0.1"
#define PORT_RCV 34343U
#define PORT_SND 34344U

#define IP_MTU_SIZE 1536

class EnaluPacketListener : public OscPacketListener
{
    protected:
        void ProcessMessage( const ReceivedMessage& m, const IpEndpointName& /*remoteEndpoint*/ )
        {
            //ReceivedMessageArgumentStream args = m.ArgumentStream();
            ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
            try{
                if( strcmp( m.AddressPattern(), "/info" ) == 0 )
                {
                    msg.clear();
                    msg = (arg++)->AsString();
                    //args >> msg >> EndMessage;
                    if( arg != m.ArgumentsEnd() )
                        std::cout << "more args exist\n";
                }
            }
            catch( Exception& e )
            {
                // any parsing errors such as unexpected argument types, or
                // missing arguments get thrown as exceptions.
                std::cout << "error while parsing message: "
                << m.AddressPattern() << ": " << e.what() << "\n";
            }
        }
    public:
        std::string msg;
};



void sendMsg(UdpTransmitSocket & transmitSocket , std::string const & msgTitle , std::string const & msg)
{
    char buffer[IP_MTU_SIZE];
    osc::OutboundPacketStream p( buffer, IP_MTU_SIZE );

    p.Clear();
    //p << osc::BeginBundleImmediate;
    p << osc::BeginMessage( msgTitle.c_str() );
    p << msg.c_str();
    p << osc::EndMessage;
    //p << osc::EndBundle;

    transmitSocket.Send( p.Data(), p.Size() );
}


void rcvThread(bool bExit)
{
    IpEndpointName ipen(ADDRESS,PORT_RCV);
    UdpReceiveSocket s(ipen);
    EnaluPacketListener pckParser;
    IpEndpointName ipenRcv;
    char * buffer = nullptr;
    int bufferSize = 0U;
    while (!bExit)
    {
        std::cout << "hello1\n";
        int i = s.ReceiveFrom(ipenRcv,buffer,bufferSize);
        if (i > 0)
        {
            std::cout << "bufferSize=" << bufferSize << " , buffer: " << buffer << std::endl;
            //we have data
            pckParser.ProcessPacket(buffer,bufferSize,ipenRcv);
            std::cout << "rcved: "  << pckParser.msg << "\n";
        }
        sleep(1);
    }
}

//int main(int argc, char* argv[])
int main(int , char**)
{
    bool bExit = false;
    UdpTransmitSocket transmitSocket( IpEndpointName( ADDRESS, PORT_SND ) );

    std::thread thr(rcvThread, std::ref(bExit));

    std::string str;
    while (!bExit)
    {
        std::cin >> str;
        if ((!str.empty()) && (str.compare("q") != 0))
            sendMsg(transmitSocket,"info",str);
        else
            bExit = true;
    }

    thr.join();

    return 0;
}
nass
  • 1,453
  • 1
  • 23
  • 38
  • 1
    It's possible to send an empty datagram, and `recv()` will then return 0. – Barmar Nov 16 '16 at 22:24
  • @Barmar I do not think I send an empty datagram here. when `sendMsg` executes, there is some string already in `str` after the `std::cin` step. – nass Nov 16 '16 at 22:27
  • @nass The zero is telling you that you did, and you aren't checking the value of `p.Size()` or the result returned by `send()`, so you don't have any basis for your belief. – user207421 Nov 16 '16 at 22:50
  • @EJP, just tested the return value of `send()`, it is not zero. So I definitely send something. and indeed as I have stated, `netcat` receives the message. That was my basis already – nass Nov 16 '16 at 23:05

1 Answers1

1
char * buffer = nullptr;
int bufferSize = 0U;

The problems are here.

    int i = s.ReceiveFrom(ipenRcv,buffer,bufferSize);

You are telling ReceiveFrom() to receive into a zero-length buffer pointed to by a null pointer, so it does, and returns zero. What else could it do? Change to:

char buffer[4096]; // or whatever you need
// ...
int i = s.ReceiveFrom(ipenRcv,buffer,sizeof buffer);
user207421
  • 305,947
  • 44
  • 307
  • 483