C++と色々

主にC++やプログラムに関する記事を投稿します。

Boost.AsioでHTTP通信

HTTP通信をするプログラムを書いてみました。WinScok2とBoost.Asioでそれぞれ書いてみました。簡単にするためにTCPで同期通信するプログラムです。WinSockの参考に「猫でもわかるWindowsプログラミング」を使ったのでアクセスするページがそうなっていますが、特にそれ以上の意味はありません。

WinSock

//WinSockでHTTP通信を行う
#include <WinSock2.h>
#include <iostream>
#include <string>
using namespace std;

int main()
{
    WSADATA wsadata;//ソケット情報を格納する構造体

    //WinSockの初期化
    if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0)
    {
        cout << "winsock startup failed.\n";
        return 1;
    }

    //指定したサービスプロバイダへのTCPソケットを作成する。
    const auto sock = socket(PF_INET, SOCK_STREAM, 0);
    if (sock == INVALID_SOCKET)
    {
        cout << "couldn't open a socket.\n";
        WSACleanup();
        return 1;
    }

    //ホスト情報を取得
    const auto server_name = "www.kumei.ne.jp";
    auto host = gethostbyname(server_name);
    if (host == nullptr)
    {
        auto addr = inet_addr(server_name);
        host = gethostbyaddr(reinterpret_cast<char*>(&addr), 4, AF_INET);
        if (host == nullptr)
        {
            cout << server_name << " is not found.\n";
            WSACleanup();
            return 1;
        }
    }

    //IPv4のソケットアドレス情報を設定する
    sockaddr_in sockadd;
    memset(&sockadd, 0, sizeof(sockadd));
    sockadd.sin_family = AF_INET;
    sockadd.sin_port = htons(80);
    sockadd.sin_addr = *(reinterpret_cast<LPIN_ADDR>(*(host->h_addr_list)));

    //指定したソケットへ接続する
    if (connect(sock, reinterpret_cast<PSOCKADDR>(&sockadd), sizeof(sockadd)) != 0)
    {
        cout << "connect failure.\n";
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    //メッセージを送信
    const string message = "GET /c_lang/index_cp.html HTTP/1.0\r\n\r\n";
    const auto res = send(sock, message.c_str(), static_cast<int>(message.size()), 0);
    if (res == SOCKET_ERROR)
    {
        cout << "send failure.\n";
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    //メッセージを受信
    char buf[1024];
    while (true)
    {
        memset(buf, '\0', sizeof(buf));
        auto size = recv(sock, buf, static_cast<int>(sizeof(buf) - 1), 0);
        cout << buf;
        //受信が終わったらループを抜ける
        if (size == 0)
        {
            break;
        }
        if (size == SOCKET_ERROR)
        {
            cout << "recieve error.\n";
            break;
        }
    }
    //ソケットの送受信を切断する
    shutdown(sock, SD_BOTH);
    //ソケットを破棄する
    closesocket(sock);
    //WinSockの解放
    WSACleanup();
}

実行結果略


Boost.Asio

#include <boost/asio.hpp>
#include <iostream>
using namespace std;
namespace asio = boost::asio;
namespace ip = asio::ip;

int main()
try
{
    asio::io_service io_service;
    
    //TCPソケットを作成する
    ip::tcp::socket sock(io_service);

    //名前解決(ホスト名からIPアドレスに変換)する
    ip::tcp::resolver resolver(io_service);
    ip::tcp::resolver::query query("www.kumei.ne.jp", "http");

    //ホスト情報を設定する
    ip::tcp::endpoint endpoint(*resolver.resolve(query));

    //ソケットへ接続
    sock.connect(endpoint);

    //メッセージを送信
    asio::streambuf request;
    ostream request_ostream(&request);
    request_ostream << "GET /c_lang/index_cp.html HTTP/1.0\r\n\r\n";
    asio::write(sock, request);

    //メッセージを受信
    asio::streambuf buffer;
    boost::system::error_code error;
    asio::read(sock, buffer, asio::transfer_all(), error);
    if (error && error != asio::error::eof)
    {
        std::cout << "receive failed: " << error.message() << std::endl;
    }
    else
    {
        cout << &buffer;
    }
}
catch (exception& e)
{
    cout << e.what();
}

実行結果略