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日からのダウンロード数:1388
Subversion
・フリーの Subversion ホスティングサービス Assemblaで、ソースコードを管理しています。
![]() |
Copyright © 2011 Round Square Inc. All rights reserved. |
---|
初めまして、出村と申します。
マルチキャストのプログラム例、参考にさせていただきました。
ありがとうございます。
また、私が以前書いたPOCOの記事をリンクに載せていただいてありがとうございます。
今はリンク切れになっていますので、私の会社のブログに元記事をアップしていきます。
今後とも、よろしくお願い申し上げます。
コメントありがとうございます。
あのPOCOの記事の作者さんからコメントを頂けるとは嬉しい限りです。
リンク切れはいずれ修正します。