Pocoライブラリは、ネイティブソケットの上位レイヤーに位置するC++用ネットワークフレームワークです。生のソケットと比較して性能面ではやや劣るものの、安全性と実用性に優れ、簡潔なAPIを提供します。UDPプロトコルでは、受信側がデータを適時に取得できない場合、そのデータは失われます。
環境セットアップ
sudo apt-get install libpoco-dev
ポート514に関する注意点
多くのサンプルコード(公式資料を含む)でポート514が使われていますが、このポートで受信を行うと I/O error が発生する可能性があります。これは、ポート514がsyslogサービス用に予約されており、バインドにはスーパーユーザー権限が必要だからです。送信自体は制限なく行えます。回避策として、ポート番号を変更するか、管理者権限で実行してください。
UDP送信サンプル
#include "Poco/Net/DatagramSocket.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Timestamp.h"
#include "Poco/DateTimeFormatter.h"
int main(int argc, char **argv)
{
Poco::Net::SocketAddress addr("localhost", 1101);
Poco::Net::DatagramSocket sock;
sock.connect(addr);
Poco::Timestamp ts;
std::string payload = Poco::DateTimeFormatter::format(ts,
"<14>%w %f %H:%M:%S Hello, world!");
sock.sendBytes(payload.data(), payload.size());
return 0;
}
UDP受信サンプル
#include "Poco/Net/DatagramSocket.h"
#include "Poco/Net/SocketAddress.h"
#include <iostream>
int main(int argc, char **argv)
{
Poco::Net::SocketAddress bindAddr("localhost", 1101);
Poco::Net::DatagramSocket rxSocket(bindAddr);
char buf[1024];
for (;;)
{
Poco::Net::SocketAddress srcAddr;
int recvLen = rxSocket.receiveFrom(buf, sizeof(buf) - 1, srcAddr);
buf[recvLen] = '\0';
std::cout << srcAddr.toString() << ": " << buf << std::endl;
}
return 0;
}
コンパイルコマンド
g++ sender.cpp -lPocoNet -lPocoFoundation -o sender
g++ receiver.cpp -lPocoNet -lPocoFoundation -o receiver
マルチキャスト送信例
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/MulticastSocket.h"
#include "Poco/DateTimeFormatter.h"
#include <iostream>
#include <cstring>
int main(int argc, char *argv[])
{
try
{
Poco::Net::SocketAddress mcastAddr("239.255.255.250", 1902);
Poco::Net::MulticastSocket mcastSock(
Poco::Net::SocketAddress(
Poco::Net::IPAddress(), mcastAddr.port()));
mcastSock.joinGroup(mcastAddr.host());
Poco::Net::SocketAddress senderAddr;
char buffer[512] = "";
Poco::Timestamp now;
std::string msg = Poco::DateTimeFormatter::format(now,
"%Y-%m-%d %H:%M:%S.%i send: Hello, world!");
mcastSock.sendTo(msg.data(), msg.size(), mcastAddr);
int recvLen = mcastSock.receiveFrom(buffer, sizeof(buffer), senderAddr);
std::cout << "Received: " << buffer << " from " << senderAddr.toString() << std::endl;
}
catch (Poco::Exception &e)
{
std::cerr << "Exception: " << e.displayText() << std::endl;
return 1;
}
return 0;
}
マルチキャストの注意点
- 「239.255.255.250」とポート1902の組み合わせはユニークな識別子として機能し、パケットキャプチャでフィルタリング可能
- 使用するポートに不要なトラフィックがないか事前確認が必要
- 同一ネットワークセグメント内かつ同一のグループアドレスを使用しているノード間でのみ通信可能
sender.toString()で送信元IPアドレスが取得可能
マルチキャスト受信例
#include <Poco/Net/DatagramSocket.h>
#include <Poco/Net/SocketAddress.h>
#include <Poco/Net/MulticastSocket.h>
#include <Poco/Net/NetworkInterface.h>
#include <iostream>
#include <vector>
int main() {
try {
Poco::Net::SocketAddress groupAddr("239.1.1.5", 9200);
Poco::Net::MulticastSocket rxSocket(Poco::Net::IPAddress::IPv4);
rxSocket.bind(Poco::Net::SocketAddress(Poco::Net::IPAddress(), groupAddr.port()), true);
Poco::Net::NetworkInterface netIf = Poco::Net::NetworkInterface::forName("eth0.10");
rxSocket.joinGroup(groupAddr.host(), netIf);
std::vector<char> dataBuf(1024);
std::cout << "Waiting for multicast on " << groupAddr.toString() << " ..." << std::endl;
while (true) {
Poco::Net::SocketAddress remoteAddr;
int bytesRead = rxSocket.receiveFrom(&dataBuf[0], dataBuf.size(), remoteAddr);
if (bytesRead > 0) {
std::string message(dataBuf.begin(), dataBuf.begin() + bytesRead);
std::cout << "From " << remoteAddr.toString() << ": " << message << std::endl;
}
}
rxSocket.leaveGroup(groupAddr.host(), netIf);
} catch (Poco::Exception& ex) {
std::cerr << "Poco Error: " << ex.displayText() << std::endl;
} catch (std::exception& ex) {
std::cerr << "Standard Error: " << ex.what() << std::endl;
} catch (...) {
std::cerr << "Unknown error occurred!" << std::endl;
}
return 0;
}
タイムスタンプユーティリティ
Poco::Timestamp currentTime;
std::string timeStr = Poco::DateTimeFormatter::format(currentTime, "%Y-%m-%d %H:%M:%S.%i ");
Poco::Int64 msSinceEpoch = currentTime.epochMicroseconds() / 1000;
// 数値を固定長文字列に変換
std::string numStr = std::to_string(msSinceEpoch);
std::stringstream ss;
ss << std::setw(13) << std::setfill('0') << numStr;
UDPパケットの優先度設定
Poco::Net::SocketAddress mcastAddr(MULTICAST_IP, MULTICAST_PORT);
Poco::Net::MulticastSocket prioritySocket(
Poco::Net::SocketAddress(LOCAL_IP, mcastAddr.port()));
int prioLevel = 4;
prioritySocket.setOption(SOL_SOCKET, SO_PRIORITY, prioLevel);