recvfrom() 在收到 udp 数据包时解锁,但 returns 0 作为读取字节的大小(使用 oscpack)
recvfrom() unblocks when a udp packet is received but returns 0 as size of read bytes (using oscpack)
这是一项测试,目的是在使用套接字的应用程序之间创建一些临时进程间通信。这些应用程序稍后将 运行 在不同的系统上,使用定制的嵌入式通信系统,但目前后者还不可用。因此,我正在寻找一种快速(甚至可能有点脏)的 C++ 方法来实现这些应用程序之间的进程间通信。应用程序将发送一些字符串(所以没什么特别的)。
我偶然发现了 oscpack,它利用 udp
来实现开放式声音控制的消息传递。我在 linux 中使用 gcc4.7.1 作为共享对象使用 make lib
编译了它。请注意,我必须在 Makefile
.
的 COPTS
变量中附加选项 -fPIC
有了共享库,我写了一个小的概念验证应用程序,它使用一个单独的线程来侦听消息,并在主线程中等待来自 stdin
的一些字符串转发它到另一个应用程序。我执行了这个应用程序的 2 个非常相似的实例。只是在第二次我交换了 PORT_RCV
和 PORT_SND
数字。
实际问题从这里开始:
我面临的问题是,在接收端,当对 osc::UdpSocket::ReceiveFrom()
的调用(最终运行 recvfrom())解除阻塞时,我得到的 return 读取字节值等于零(0).此外 char * data
指针仍指向零。所以本质上我没有收到来自发件人应用程序的字符串,即使 recvfrom() 在正确的时间解除阻塞。
我从手册页中了解到,当发送方关闭连接时,recv 和 recvfrom 可以 return 值为 0。但在这种情况下,发件人使用的是 udp,即无连接...连接 :),所以我不确定它是否适用于此。
我试过使用netcat
在相应的端口监听udp消息,并验证至少发件人部分工作正常。事实上 netcat -u -l -p <sender port of the running instance>
,我确实收到了我输入的消息。所以问题可能与接收端有关。
问题是:我是否正确使用了 recvfrom?
请查找附加到进程间通信测试应用程序的代码(真正的全双工信使)。要执行其中的两个,首先下载 oscpack
库并将其编译为库。然后将下面的源复制到两个文件中,并交换第二个源文件中的 PORT_RCV
和 PORT_SND
数字。
然后编译每个:
#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
然后执行它们并输入一个词,按回车键并期望(不)看到它出现在其他应用程序中。
#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;
}
char * buffer = nullptr;
int bufferSize = 0U;
问题就在这里
int i = s.ReceiveFrom(ipenRcv,buffer,bufferSize);
您告诉 ReceiveFrom()
接收到空指针指向的零长度缓冲区,它确实如此,并且 returns 为零。它还能做什么?更改为:
char buffer[4096]; // or whatever you need
// ...
int i = s.ReceiveFrom(ipenRcv,buffer,sizeof buffer);
这是一项测试,目的是在使用套接字的应用程序之间创建一些临时进程间通信。这些应用程序稍后将 运行 在不同的系统上,使用定制的嵌入式通信系统,但目前后者还不可用。因此,我正在寻找一种快速(甚至可能有点脏)的 C++ 方法来实现这些应用程序之间的进程间通信。应用程序将发送一些字符串(所以没什么特别的)。
我偶然发现了 oscpack,它利用 udp
来实现开放式声音控制的消息传递。我在 linux 中使用 gcc4.7.1 作为共享对象使用 make lib
编译了它。请注意,我必须在 Makefile
.
COPTS
变量中附加选项 -fPIC
有了共享库,我写了一个小的概念验证应用程序,它使用一个单独的线程来侦听消息,并在主线程中等待来自 stdin
的一些字符串转发它到另一个应用程序。我执行了这个应用程序的 2 个非常相似的实例。只是在第二次我交换了 PORT_RCV
和 PORT_SND
数字。
实际问题从这里开始:
我面临的问题是,在接收端,当对 osc::UdpSocket::ReceiveFrom()
的调用(最终运行 recvfrom())解除阻塞时,我得到的 return 读取字节值等于零(0).此外 char * data
指针仍指向零。所以本质上我没有收到来自发件人应用程序的字符串,即使 recvfrom() 在正确的时间解除阻塞。
我从手册页中了解到,当发送方关闭连接时,recv 和 recvfrom 可以 return 值为 0。但在这种情况下,发件人使用的是 udp,即无连接...连接 :),所以我不确定它是否适用于此。
我试过使用netcat
在相应的端口监听udp消息,并验证至少发件人部分工作正常。事实上 netcat -u -l -p <sender port of the running instance>
,我确实收到了我输入的消息。所以问题可能与接收端有关。
问题是:我是否正确使用了 recvfrom?
请查找附加到进程间通信测试应用程序的代码(真正的全双工信使)。要执行其中的两个,首先下载 oscpack
库并将其编译为库。然后将下面的源复制到两个文件中,并交换第二个源文件中的 PORT_RCV
和 PORT_SND
数字。
然后编译每个:
#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
然后执行它们并输入一个词,按回车键并期望(不)看到它出现在其他应用程序中。
#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;
}
char * buffer = nullptr;
int bufferSize = 0U;
问题就在这里
int i = s.ReceiveFrom(ipenRcv,buffer,bufferSize);
您告诉 ReceiveFrom()
接收到空指针指向的零长度缓冲区,它确实如此,并且 returns 为零。它还能做什么?更改为:
char buffer[4096]; // or whatever you need
// ...
int i = s.ReceiveFrom(ipenRcv,buffer,sizeof buffer);