ヨーキョクデイ

いろいろ雑食

boost::asio で UDP 通信したい

オレオレ UDP クラス(ただし手抜き)をでっちあげた。

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>

const size_t BUF_SIZE = 1024;

class UDPSocket{
private:
    boost::asio::ip::udp::socket sock;
    
    void send_handler(const boost::system::error_code& error, std::size_t len){
        // do nothing
    }
    void recv_handler(const boost::system::error_code &error, std::size_t len,
            boost::array<char, BUF_SIZE> buf, std::string &out){
        out.assign(buf.data(), len);
    }

public:
    UDPSocket(boost::asio::io_service &io_service)
        : sock(io_service){
    }
    ~UDPSocket(){
        close();
    }
    
    void bind(){
        sock.open(boost::asio::ip::udp::v4());
        sock.bind(boost::asio::ip::udp::endpoint());
    }
    void bind(unsigned short port){
        sock.open(boost::asio::ip::udp::v4());
        sock.bind(boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), port));
    }
    void close(){
        sock.close();
    }

    // asynchronous
    void a_send_to(const std::string &request, const char *ipaddr, unsigned short port){
        sock.async_send_to(boost::asio::buffer(request),
            boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string(ipaddr), port),
            boost::bind(&UDPSocket::send_handler,
                this,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred));
    }
    void a_recv_from(std::string &response){
        boost::asio::ip::udp::endpoint sender_endpoint;
        boost::array<char, BUF_SIZE> buf;
        sock.async_receive_from(boost::asio::buffer(buf), sender_endpoint,
            boost::bind(&UDPSocket::recv_handler,
                this,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred,
                boost::ref(buf),
                boost::ref(response)));
    }

    // synchronous
    size_t send_to(const std::string &request, const char *ipaddr, unsigned short port){
        size_t len = 0;
        len = sock.send_to(boost::asio::buffer(request),
            boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string(ipaddr), port));
        return len;
    }
    size_t recv_from(std::string &response){
        size_t len = 0;
        boost::asio::ip::udp::endpoint sender_endpoint;
        boost::array<char, BUF_SIZE> buf;
        len = sock.receive_from(boost::asio::buffer(buf), sender_endpoint);
        response.assign(buf.data(), len);
        return len;
    }
};

int main(){
    boost::asio::io_service io_service;
    UDPSocket udp(io_service);
    udp.bind();

    std::string request = "M-SEARCH * HTTP/1.1\r\n"
            "MX: 3\r\n"
            "HOST: 239.255.255.250:1900\r\n"
            "MAN: \"ssdp:discover\"\r\n"
            "ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n\r\n";
    std::string response;

    // asynchronous
    std::cout << "ASYNCHRONOUS" << std::endl;
    std::cout << "-----" << std::endl;
    udp.a_send_to(request, "239.255.255.250", 1900);
    udp.a_recv_from(response);
    io_service.run();  // important!
    std::cout << response << std::endl;

    response.clear();

    // synchronous
    std::cout << "SYNCHRONOUS" << std::endl;
    std::cout << "-----" << std::endl;
    udp.send_to(request, "239.255.255.250", 1900);
    udp.recv_from(response);
    std::cout << response << std::endl;

    return 0;
}