Poco::Net::MulticastSocket

Poco::Net::MulticastSocket を紹介します。

このクラスは、名前のとおり Multicast のソケットを提供しています。

今回のサンプルは、MulticastSocket の Sender と Receiver、さらにそれらを起動するものと、3つのソースがあります。

MulticastSocketSender.cpp

・MulticastSocket を送出。
Poco::Util::ServerApplication を使用。
・SenderTask を立ち上げ、その中で周期的に MulticastSocket を送出。
・最後の行の POCO_SERVER_MAIN は、その中に main() エントリーポイントがあるマクロ。
 (Util/include/Poco/Util/ServerApplication.h 参照)

#include <Poco/Util/ServerApplication.h>
#include <Poco/Task.h>
#include <Poco/TaskManager.h>
#include <Poco/Net/TCPServerConnection.h>
#include <Poco/Net/TCPServerConnectionFactory.h>
#include <Poco/Net/MulticastSocket.h>
#include <Poco/NumberFormatter.h>
#include <Poco/Net/NetworkInterface.h>
#include <Poco/Net/SocketAddress.h>
#include <Poco/Format.h>
#include <Poco/NumberParser.h>
 
#include <string>
#include <iostream>
 
const long	kWaitMSec(500);
 
class SenderTask: public Poco::Task
{
public:
	SenderTask(const std::vector<std::string>& args) :	// args[0]: MulticastAddress, args[1]: MulticastPort, args[2]: WaitingPort
		Poco::Task			("SenderTask")
	,	m_family			(Poco::Net::IPAddress(args[0]).family())
	,	m_port				(Poco::NumberParser::parseUnsigned(args[1]))
	,	m_waitingPort			(Poco::NumberParser::parseUnsigned(args[2]))
	,	m_multicastSocket		(Poco::Net::MulticastSocket(m_family))
	,	m_pMulticastSocketAddress	(NULL)
	{
	}
 
	~SenderTask()
	{
		if(NULL != m_pMulticastSocketAddress)
		{
			delete m_pMulticastSocketAddress;
		}
	}
 
	void runTask()
	{
		Poco::Logger& logger = Poco::Util::Application::instance().logger();
 
		std::string hostAddress;
 
		Poco::Net::NetworkInterface::NetworkInterfaceList list = Poco::Net::NetworkInterface::list();
		if(!list.empty())
		{
			for(Poco::Net::NetworkInterface::NetworkInterfaceList::const_iterator itr=list.begin(); itr!=list.end(); ++itr)
			{
				if(	!itr->address().isLoopback()
					&& (m_family == itr->address().family())
				#if !defined(POCO_OS_FAMILY_WINDOWS)
					&& ('e' == itr->name()[0])
				#endif
					)
				{
					hostAddress += itr->address().toString();
					if(Poco::Net::IPAddress::IPv6 == itr->address().family())
					{
						hostAddress += "%";
						hostAddress += itr->name();
					}
					logger.information(Poco::format("   SenderTask: %s:%hu", hostAddress, m_port));
					m_pMulticastSocketAddress = new Poco::Net::SocketAddress(hostAddress, m_port);
					break;
				}
			}
		}
 
		if(NULL != m_pMulticastSocketAddress)
		{
			while(!isCancelled())
			{
				m_multicastMessage = Poco::format(	"SenderTask?ipaddr=%s&port=%hu",
									hostAddress,
									m_waitingPort);
				std::size_t n = m_multicastSocket.sendTo(	m_multicastMessage.c_str(),
										static_cast<int>(m_multicastMessage.length()),
										*m_pMulticastSocketAddress	);
				if(n != m_multicastMessage.length())
				{
					logger.information("   SenderTask: send error");
				}
				sleep(kWaitMSec);
			}
		}
	}
 
private:
	Poco::Net::IPAddress::Family	m_family;
	Poco::UInt16			m_port;
	Poco::UInt16			m_waitingPort;
	Poco::Net::MulticastSocket	m_multicastSocket;
	Poco::Net::SocketAddress*	m_pMulticastSocketAddress;
	std::string			m_multicastMessage;
};
 
class MulticastSocketSender: public Poco::Util::ServerApplication
{
public:
	MulticastSocketSender()
	{
	}
 
protected:
	void initialize(Application& self)
	{
		loadConfiguration(); // load default configuration files, if present
		Poco::Util::ServerApplication::initialize(self);
		logger().information("   - MulticastSocketSender starting up");
	}
 
	void uninitialize()
	{
		logger().information("   - MulticastSocketSender shutting down");
		Poco::Util::ServerApplication::uninitialize();
	}
 
	int main(const std::vector<std::string>& args)
	{
		Poco::TaskManager tm;
		tm.start(new SenderTask(args));
		waitForTerminationRequest();
		tm.cancelAll();
		tm.joinAll();
 
		return Application::EXIT_OK;
	}
};
 
POCO_SERVER_MAIN(MulticastSocketSender)

MulticastSocketReceiver.cpp

・MulticastSocket を受信。
Poco::Util::ServerApplication を使用。
・ReceiverTask を立ち上げ、その中で MulticastSocket の受信待ち。
・最後の行の POCO_SERVER_MAIN は、その中に main() エントリーポイントがあるマクロ。
 (Util/include/Poco/Util/ServerApplication.h 参照)

#include <Poco/Util/ServerApplication.h>
#include <Poco/Task.h>
#include <Poco/TaskManager.h>
#include <Poco/Net/Net.h>
#include <Poco/Net/MulticastSocket.h>
#include <Poco/Net/SocketAddress.h>
#include <Poco/Net/NetworkInterface.h>
#include <Poco/Net/IPAddress.h>
#include <Poco/Format.h>
#include <Poco/NumberParser.h>
 
#include <string>
#include <iostream>
 
const Poco::Timespan::TimeDiff KWaitUSec(250000);	// 250msec
 
class ReceiverTask: public Poco::Task
{
public:
	ReceiverTask(const std::vector<std::string>& args) :	// args[0]: MulticastAddress, args[1]: MulticastPort
		Poco::Task("ReceiverTask")
	,	m_family		(Poco::Net::IPAddress(args[0]).family())
	,	m_port			(Poco::NumberParser::parseUnsigned(args[1]))
	,	m_multicastSocket	(Poco::Net::MulticastSocket(m_family))
	,	m_socketAddres		(args[0], m_port)
	,	m_if			(findInterface(m_family))
	{
		Poco::Logger& logger = Poco::Util::Application::instance().logger();
		logger.information(Poco::format("  ReceiverTask start listening %s:%hu", args[0], m_port));
 
		m_multicastSocket.bind(Poco::Net::SocketAddress(Poco::Net::IPAddress(m_family), m_socketAddres.port()), true);
		m_multicastSocket.joinGroup(m_socketAddres.host(), m_if);
	}
 
	~ReceiverTask()
	{
	}
 
	void runTask()
	{
		Poco::Logger& logger = Poco::Util::Application::instance().logger();
		Poco::Timespan span(KWaitUSec);
		while(!isCancelled())
		{
			if(m_multicastSocket.poll(span, Poco::Net::Socket::SELECT_READ))
			{
				try
				{
					char buffer[256];
					Poco::Net::SocketAddress sender;
					int n = m_multicastSocket.receiveFrom(buffer, sizeof(buffer), sender);
					if(0 != n)
					{
						buffer[n] = 0;
						logger.information(Poco::format("   ReceiverTask: received %d bytes (%s)", n, std::string(buffer)));
					}
				//	m_multicastSocket.sendTo(buffer, n, sender);	// for echo back
				}
				catch(Poco::Exception& exc)
				{
					logger.information(Poco::format("   ReceiverTask: %s", exc.displayText()));
				}
			}
		}
	}
 
private:
	static Poco::Net::NetworkInterface findInterface(Poco::Net::IPAddress::Family family)
	{
		Poco::Net::NetworkInterface::NetworkInterfaceList ifs = Poco::Net::NetworkInterface::list();
		for(Poco::Net::NetworkInterface::NetworkInterfaceList::const_iterator itr=ifs.begin(); itr!=ifs.end(); ++itr)
		{
			if((family == itr->address().family()) && itr->address().isUnicast() && !itr->address().isLoopback())
			{
				if(	(Poco::Net::IPAddress::IPv4 == itr->address().family()) ||
					(Poco::Net::IPAddress::IPv6 == itr->address().family() &&
						std::string::npos != itr->address().toString().find("FE80::2"))	)
				// NOTE: "FE80::2" disables strange loppback address on Mac (fe80::1 <- usually ::1)
				{
					return *itr;
				}
			}
		}
		return Poco::Net::NetworkInterface();
	}
 
	Poco::Net::IPAddress::Family	m_family;
	Poco::UInt16			m_port;
	Poco::Net::MulticastSocket	m_multicastSocket;
	Poco::Net::SocketAddress	m_socketAddres;
	Poco::Net::NetworkInterface	m_if;
};
 
class MulticastSocketReceiver: public Poco::Util::ServerApplication
{
public:
	MulticastSocketReceiver()
	{
	}
 
protected:
	void initialize(Application& self)
	{
		loadConfiguration(); // load default configuration files, if present
		Poco::Util::ServerApplication::initialize(self);
		logger().information("   - MulticastSocketReceiver starting up");
	}
 
	void uninitialize()
	{
		logger().information("   - MulticastSocketReceiver shutting down");
		Poco::Util::ServerApplication::uninitialize();
	}
 
	int main(const std::vector<std::string>& args)
	{
		Poco::TaskManager tm;
		tm.start(new ReceiverTask(args));
		waitForTerminationRequest();
		tm.cancelAll();
		tm.joinAll();
 
		return Application::EXIT_OK;
	}
};
 
POCO_SERVER_MAIN(MulticastSocketReceiver)

MulticastSocketTest.cpp

・MulticastSocket の Receiver と Sender プロセスを起動し、しばらく待った後にそれぞれを終了。

#include <Poco/Process.h>
#include <Poco/Pipe.h>
#include <Poco/PipeStream.h>
#include <Poco/StreamCopier.h>
#include <Poco/Format.h>
#include <Poco/Runnable.h>
#include <Poco/Thread.h>
#include <Poco/Net/Net.h>
#include <Poco/Net/IPAddress.h>
#include <Poco/String.h>
 
#include <string>
#include <vector>
#include <iostream>
 
#include "ScopedLogMessage.h"
#include "PrepareConsoleLogger.h"
 
#if defined(POCO_OS_FAMILY_WINDOWS)
const std::string kCommandTable[] =	{"MulticastSocketTestReceiver.exe",
					 "MulticastSocketTestSender.exe"};
#else
const std::string kCommandTable[] =	{"./MulticastSocketTestReceiver",
					 "./MulticastSocketTestSender"};
#endif
 
const std::size_t kNumCommands = sizeof(kCommandTable)/sizeof(kCommandTable[0]);
 
const char* kMulticastAddresses[] = {"239.255.1.2", "FF02::1"};
const std::string kMulticastPort("12345");
const std::string kWaitingPort("23456");
 
class ProcessLauncher: public Poco::Runnable
{
public:
	ProcessLauncher(ScopedLogMessage& msg, const std::string& command, const std::vector<std::string>& args) :
		m_msg(msg)
	,	m_command(command)
	,	m_pPh(NULL)
	,	m_Pid(0)
	,	m_args(args)
	{
	}
 
	~ProcessLauncher()
	{
		int rc = m_pPh->wait();
		m_msg.Message(Poco::format(" \"%s\" terminated with return code = %d", m_command, rc));
		delete m_pPh;
	}
 
	void run()
	{
		std::string args;
		for(std::size_t i=0; i<m_args.size(); ++i)
		{
			args += " " + m_args[i];
		}
		m_msg.Message(Poco::format(" launch \"%s%s\"", m_command, args));
		Poco::Pipe outPipe;
		m_pPh = new Poco::ProcessHandle(Poco::Process::launch(m_command, m_args, 0, &outPipe, 0));
		m_Pid = m_pPh->id();
		Poco::PipeInputStream istr(outPipe);
		Poco::StreamCopier::copyStream(istr, std::cout);
	}
 
	void stop()
	{
		m_msg.Message(Poco::format(" \"%s\" requestTermination", m_command));
		Poco::Process::requestTermination(m_Pid);
	}
 
private:
	ScopedLogMessage&		m_msg;
	const std::string&		m_command;
	Poco::ProcessHandle*		m_pPh;
	Poco::Process::PID		m_Pid;
	const std::vector<std::string>	m_args;
};
 
int main(int argc, char** argv)
{
	PrepareConsoleLogger logger(Poco::Logger::ROOT, Poco::Message::PRIO_INFORMATION);
 
	ScopedLogMessage msg("MulticastSocketTest ", "start", "end");
 
	Poco::Thread thread[kNumCommands];
	ProcessLauncher* pLauncher[kNumCommands];
 
	int addressIndex = 0;
	if(1 < argc)
	{
		if("ipv6" == Poco::toLower(std::string(argv[1])))	++addressIndex;
	}
 
	for(std::size_t i=0; i<kNumCommands; ++i)
	{
		std::vector<std::string> args;
		args.push_back(kMulticastAddresses[addressIndex]);
		args.push_back(kMulticastPort);
		args.push_back(kWaitingPort);
		pLauncher[i] = new ProcessLauncher(msg, kCommandTable[i], args);
		thread[i].start(*pLauncher[i]);
		Poco::Thread::sleep(200);
	}
 
	Poco::Thread::sleep(2000);
 
	for(std::size_t i=0; i<kNumCommands; ++i)
	{
		std::size_t index = kNumCommands-1-i;
 
		pLauncher[index]->stop();
		thread[index].join();
		delete pLauncher[index];
	}
 
	return 0;
}

Results of execution

・On Linux

$ ./MulticastSocketTest
[0] MulticastSocketTest start
[1]  launch "./MulticastSocketTestReceiver 239.255.1.2 12345 23456"
   - MulticastSocketReceiver starting up
  ReceiverTask start listening 239.255.1.2:12345
[2]  launch "./MulticastSocketTestSender 239.255.1.2 12345 23456"
   - MulticastSocketSender starting up
   SenderTask: 172.16.250.128:12345
   ReceiverTask: received 43 bytes (SenderTask?ipaddr=172.16.250.128&port=23456)
   ReceiverTask: received 43 bytes (SenderTask?ipaddr=172.16.250.128&port=23456)
   ReceiverTask: received 43 bytes (SenderTask?ipaddr=172.16.250.128&port=23456)
   ReceiverTask: received 43 bytes (SenderTask?ipaddr=172.16.250.128&port=23456)
   ReceiverTask: received 43 bytes (SenderTask?ipaddr=172.16.250.128&port=23456)
[0]  "./MulticastSocketTestSender" requestTermination
   - MulticastSocketSender shutting down
[0]  "./MulticastSocketTestSender" terminated with return code = 0
[0]  "./MulticastSocketTestReceiver" requestTermination
   - MulticastSocketReceiver shutting down
[0]  "./MulticastSocketTestReceiver" terminated with return code = 0
[0] MulticastSocketTest end
 
$ ./MulticastSocketTest ipv6
[0] MulticastSocketTest start
[1]  launch "./MulticastSocketTestReceiver FF02::1 12345 23456"
   - MulticastSocketReceiver starting up
  ReceiverTask start listening FF02::1:12345
[2]  launch "./MulticastSocketTestSender FF02::1 12345 23456"
   - MulticastSocketSender starting up
   SenderTask: FE80::20C:29FF:FEFF:E49A%eth0:12345
   ReceiverTask: received 58 bytes (SenderTask?ipaddr=FE80::20C:29FF:FEFF:E49A%eth0&port=23456)
   ReceiverTask: received 58 bytes (SenderTask?ipaddr=FE80::20C:29FF:FEFF:E49A%eth0&port=23456)
   ReceiverTask: received 58 bytes (SenderTask?ipaddr=FE80::20C:29FF:FEFF:E49A%eth0&port=23456)
   ReceiverTask: received 58 bytes (SenderTask?ipaddr=FE80::20C:29FF:FEFF:E49A%eth0&port=23456)
   ReceiverTask: received 58 bytes (SenderTask?ipaddr=FE80::20C:29FF:FEFF:E49A%eth0&port=23456)
[0]  "./MulticastSocketTestSender" requestTermination
   - MulticastSocketSender shutting down
[0]  "./MulticastSocketTestSender" terminated with return code = 0
[0]  "./MulticastSocketTestReceiver" requestTermination
   - MulticastSocketReceiver shutting down
[0]  "./MulticastSocketTestReceiver" terminated with return code = 0
[0] MulticastSocketTest end

・Macintosh OSX 10.6.6

$ ./MulticastSocketTest
[0] MulticastSocketTest start
[1]  launch "./MulticastSocketTestReceiver 239.255.1.2 12345 23456"
   - MulticastSocketReceiver starting up
  ReceiverTask start listening 239.255.1.2:12345
[2]  launch "./MulticastSocketTestSender 239.255.1.2 12345 23456"
   - MulticastSocketSender starting up
   SenderTask: 192.168.1.135:12345
   ReceiverTask: received 42 bytes (SenderTask?ipaddr=192.168.1.135&port=23456)
   ReceiverTask: received 42 bytes (SenderTask?ipaddr=192.168.1.135&port=23456)
   ReceiverTask: received 42 bytes (SenderTask?ipaddr=192.168.1.135&port=23456)
   ReceiverTask: received 42 bytes (SenderTask?ipaddr=192.168.1.135&port=23456)
   ReceiverTask: received 42 bytes (SenderTask?ipaddr=192.168.1.135&port=23456)
[0]  "./MulticastSocketTestSender" requestTermination
   - MulticastSocketSender shutting down
[0]  "./MulticastSocketTestSender" terminated with return code = 0
[0]  "./MulticastSocketTestReceiver" requestTermination
   - MulticastSocketReceiver shutting down
[0]  "./MulticastSocketTestReceiver" terminated with return code = 0
[0] MulticastSocketTest end
 
$ ./MulticastSocketTest ipv6
[0] MulticastSocketTest start
[1]  launch "./MulticastSocketTestReceiver FF02::1 12345 23456"
   - MulticastSocketReceiver starting up
  ReceiverTask start listening FF02::1:12345
[2]  launch "./MulticastSocketTestSender FF02::1 12345 23456"
   - MulticastSocketSender starting up
   SenderTask: FE80::216:CBFF:FEB0:AAE4%en0:12345
   ReceiverTask: received 57 bytes (SenderTask?ipaddr=FE80::216:CBFF:FEB0:AAE4%en0&port=23456)
   ReceiverTask: received 57 bytes (SenderTask?ipaddr=FE80::216:CBFF:FEB0:AAE4%en0&port=23456)
   ReceiverTask: received 57 bytes (SenderTask?ipaddr=FE80::216:CBFF:FEB0:AAE4%en0&port=23456)
   ReceiverTask: received 57 bytes (SenderTask?ipaddr=FE80::216:CBFF:FEB0:AAE4%en0&port=23456)
   ReceiverTask: received 57 bytes (SenderTask?ipaddr=FE80::216:CBFF:FEB0:AAE4%en0&port=23456)
[0]  "./MulticastSocketTestSender" requestTermination
   - MulticastSocketSender shutting down
[0]  "./MulticastSocketTestSender" terminated with return code = 0
[0]  "./MulticastSocketTestReceiver" requestTermination
   - MulticastSocketReceiver shutting down
[0]  "./MulticastSocketTestReceiver" terminated with return code = 0
[0] MulticastSocketTest end

・On Windows XP sp3

MulticastSocketTest.exe
[0] MulticastSocketTest start
[1]  launch "MulticastSocketTestReceiver.exe 239.255.1.2 12345 23456"
   - MulticastSocketReceiver starting up
[2]  launch "MulticastSocketTestSender.exe 239.255.1.2 12345 23456"
   - MulticastSocketSender starting up
  ReceiverTask start listening 239.255.1.2:12345
   SenderTask: 172.16.250.130:12345
   ReceiverTask: received 43 bytes (SenderTask?ipaddr=172.16.250.130&port=23456)
   ReceiverTask: received 43 bytes (SenderTask?ipaddr=172.16.250.130&port=23456)
   ReceiverTask: received 43 bytes (SenderTask?ipaddr=172.16.250.130&port=23456)
   ReceiverTask: received 43 bytes (SenderTask?ipaddr=172.16.250.130&port=23456)
[0]  "MulticastSocketTestSender.exe" requestTermination
   - MulticastSocketSender shutting down
[0]  "MulticastSocketTestSender.exe" terminated with return code = 0
[0]  "MulticastSocketTestReceiver.exe" requestTermination
   - MulticastSocketReceiver shutting down
[0]  "MulticastSocketTestReceiver.exe" terminated with return code = 0
[0] MulticastSocketTest end

Downloads

ここをクリックすると、makefile や VC++ プロジェクトなど一式がダウンロードできます。
(2013.05.31 updated)
・2011年2月27日からのダウンロード数:946

Subversion

・フリーの Subversion ホスティングサービス Assemblaで、ソースコードを管理しています。

Powered by POCO Copyright © 2011 Round Square Inc. All rights reserved.


  1. 初めまして、出村と申します。
    マルチキャストのプログラム例、参考にさせていただきました。
    ありがとうございます。

    また、私が以前書いたPOCOの記事をリンクに載せていただいてありがとうございます。
    今はリンク切れになっていますので、私の会社のブログに元記事をアップしていきます。
    今後とも、よろしくお願い申し上げます。

  2. コメントありがとうございます。
    あのPOCOの記事の作者さんからコメントを頂けるとは嬉しい限りです。
    リンク切れはいずれ修正します。

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">