recvfrom() разблокирует при получении пакета udp, но возвращает 0 как размер прочитанных байтов (используя oscpack)
Это тест для создания некоторого временного межпроцессного взаимодействия между приложениями с использованием сокетов. Позже эти приложения будут работать в разных системах, используя настроенную встроенную систему связи, но пока последняя не доступна. В результате я ищу быстрый, возможно, даже немного грязный, способ реализации межпроцессного взаимодействия между этими приложениями. Приложения будут отправлять несколько строк (так что ничего особенного).
Я наткнулся на оспак, который использует udp
реализовать передачу сообщений для открытого управления звуком. Я скомпилировал его в Linux с gcc4.7.1 как общий объект, используя make lib
, Обратите внимание, что я должен добавить опцию -fPIC
в COPTS
переменная в Makefile
,
Имея общую библиотеку, я написал небольшое приложение для проверки концепции, в котором для прослушивания сообщений используется отдельный поток, а в основном потоке он ожидает какую-то строку из stdin
переслать его в другое приложение. Я выполняю 2 очень похожие экземпляры этого приложения. Просто во втором случае я поменял местами PORT_RCV
а также PORT_SND
номера.
Актуальная проблема начинается здесь:
Проблема, с которой я сталкиваюсь, заключается в том, что на приемном конце, когда вызов osc::UdpSocket::ReceiveFrom()
(который в конечном итоге запускает recvfrom()) разблокирует, я получаю возвращаемое значение прочитанных байтов, равное нулю (0). Так же char * data
указатель по-прежнему указывает на ноль. По сути, я не получил строку из приложения отправителя, хотя функция recvfrom () разблокирована в нужное время.
Из страниц справочника я прочитал, что recv и recvfrom могут возвращать значение 0, когда отправитель закрыл соединение. Но отправитель в этом случае использует udp, т.е. соединение без соединения...:), поэтому я не уверен, применимо ли это здесь.
Я пытался использовать netcat
прослушивать сообщения udp в соответствующем порту и проверять, что хотя бы часть отправителя работает. Действительно с netcat -u -l -p <sender port of the running instance>
Я получаю сообщения, которые я печатаю. Так что, вероятно, проблема связана с получателем.
Вопрос: правильно ли я использую recvfrom?
пожалуйста, прикрепите код к тестовому приложению межпроцессного взаимодействия (на самом деле это дуплексный мессенджер). Чтобы выполнить 2 из них, сначала загрузите и скомпилируйте как библиотеку oscpack
библиотека. Затем скопируйте приведенный ниже источник в два файла и поменяйте местами PORT_RCV
а также PORT_SND
цифры на 2-й исходный файл.
Затем скомпилируйте каждый с:
#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;
}
1 ответ
char * buffer = nullptr;
int bufferSize = 0U;
Проблемы здесь.
int i = s.ReceiveFrom(ipenRcv,buffer,bufferSize);
Вы говорите ReceiveFrom()
получить в буфер нулевой длины, на который указывает нулевой указатель, так он и возвращает ноль. Что еще это может сделать? Изменить на:
char buffer[4096]; // or whatever you need
// ...
int i = s.ReceiveFrom(ipenRcv,buffer,sizeof buffer);