Boost.Asioで名前解決（非同期）

[前回の続き]
(https://qiita.com/tako3pro/items/08961c5dc7a8d398b859)

#使用したツールなど
前の記事を参照

#やりたかったこと
1. 「非同期」にする。
2. 「POST形式」で送信する。
3. 「クラス」にする。

#コード
<b>クライアント：</b>

```main.cpp
#include <iostream>
#include <vector>
#include <iomanip>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/algorithm/string.hpp>
#include "json11.hpp"

using namespace std;
namespace asio = boost::asio;
using asio::ip::tcp;

class Client {
	asio::io_service& io_service_;
	tcp::socket socket_;
	tcp::resolver resolver_;

	asio::streambuf sendbuf_;
	asio::streambuf recvbuf_;

	int value1, value2;

	const string post = "addapp.php";
	const string host = "127.0.0.1";

public:
	Client(asio::io_service& io_service, int v1, int v2)
		: io_service_(io_service),
		socket_(io_service),
		resolver_(io_service),
		value1(v1),
		value2(v2)
	{
	}

	void connect()
	{
		tcp::resolver::query query(host, "http");

		resolver_.async_resolve(
			query,
			boost::bind(&Client::on_resolve, this,
				asio::placeholders::error,
				asio::placeholders::iterator));
	}

private:
	void on_resolve(const boost::system::error_code& error,
		tcp::resolver::iterator endpoint_iterator)
	{
		/*if (error) {
			cout << "resolve failed: " << error.message() << endl;
			return;
		}*/

		asio::async_connect(
			socket_,
			endpoint_iterator,
			boost::bind(&Client::on_connect, this, asio::placeholders::error));
	}

	void on_connect(const boost::system::error_code& error)
	{
		/*if (error) {
			cout << "connect error : " << error.message() << endl;
		}
		else {
			cout << "connect!" << endl;
		}*/

		//リクエストを送信
		async_send();

		//レスポンスを受信
		async_recv();
	}

	void async_send() {;
		ostream request_stream(&sendbuf_);
		string query = "value1=" + to_string(value1) + "&value2=" + to_string(value2);

		request_stream << "POST "  << post << " HTTP/1.1\r\n";
		request_stream << "Host: " << host << "\r\n";
		request_stream << "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n";
		request_stream << "Content-Length: " << query.length() << "\r\n";
		request_stream << "Connection: Close\r\n";
		request_stream << "\r\n";
		request_stream << query << "\r\n";

		asio::async_write(socket_, sendbuf_.data(), boost::bind(&Client::send_end, this, asio::placeholders::error));
	}

	void send_end(const boost::system::error_code& error) {
		//cout << "request : " << asio::buffer_cast<const char*>(sendbuf_.data()) << endl;

		sendbuf_.consume(sendbuf_.size());
	}

	void async_recv() {
		asio::async_read(socket_, recvbuf_, asio::transfer_all(), boost::bind(&Client::recv_end, this, asio::placeholders::error));
	}

	void recv_end(const boost::system::error_code& error) {
		//cout << "response : " << asio::buffer_cast<const char*>(recvbuf_.data()) << endl;

		string_to_json(asio::buffer_cast<const char*>(recvbuf_.data()));

		recvbuf_.consume(recvbuf_.size());
	}

	void string_to_json(string str) {
		vector<string> res;
		res = boost::split(res, str, boost::is_any_of("\r\n\r\n"));

		string err;
		const json11::Json jsonData = json11::Json::parse(res[res.size() - 1], err);

		auto jsonArray = jsonData.array_items();

		cout << "    id value1 value2    ans" << endl;
		for (auto &item : jsonArray) {
			cout << setw(6) << right << item["id"].string_value() << " ";
			cout << setw(6) << right << item["value1"].string_value() << " ";
			cout << setw(6) << right << item["value2"].string_value() << " ";
			cout << setw(6) << right << item["ans"].string_value() << '\n';
		}
	}
};

int main()
{
	asio::io_service io_service;

	int value1, value2;
	cin >> value1 >> value2;

	Client client(io_service, value1, value2);
	client.connect();

	io_service.run();
}
```

<b>サーバー：</b>

```add.php
<?php

//計算する値を入力
$isInput = TRUE;
if(isset($_POST['value1'])){
	$value1 = intval($_POST['value1']);
}
else {
	$isInput = FALSE;
}
if(isset($_POST['value2'])){
	$value2 = intval($_POST['value2']);
}
else {
	$isInput = FALSE;
}

//DBの設定
$mysql = mysqli_connect('localhost', 'root', '') or die(mysqli_error($mysql));
mysqli_select_db($mysql, 'calc_db');
mysqli_query($mysql, 'SET NAMES UTF8');

//入力があるならデータをDBに追加
if($isInput){
	//結果を計算
	$ans = $value1 + $value2;

	//DBにデータを挿入
	$insert = sprintf('INSERT INTO result SET value1=%d,value2=%d,ans=%d',
			mysqli_real_escape_string($mysql, $value1),
			mysqli_real_escape_string($mysql, $value2),
			mysqli_real_escape_string($mysql, $ans)
	);
	mysqli_query($mysql, $insert) or die(mysqli_error($mysql));
}

//DBからデータを降順で取得
$request = sprintf('SELECT * FROM result');
$result = mysqli_query($mysql, $request) or die(mysqli_error($mysql));

$ansList = array();
while($row = mysqli_fetch_assoc($result)){
	$ansList[] = array(
		'id'=>$row['id'],
		'value1'=>$row['value1'],
		'value2'=>$row['value2'],
		'ans'=>$row['ans']
	);
}

//jsonで出力
$jsonData = json_encode($ansList);
header("Content-Type: application/json; charset=utf-8");
echo $jsonData;
?>
```

#変更点など
出力結果は前回と同じである。

<b>main.cpp</b>は、目的である「非同期」「POST形式」「クラス」を満たすようにした。
エラー発生時のコメントは表示しない。

<b>app.php</b>は、「\$_GET」の部分を「\$_POST」にしただけである。

#まとめ
この書き方が正しいかは分からないが取り敢えず実行はできた。
これを使って簡単なゲームでも作りたい。

#参考にしたサイト
・[ネットワーク - TCP]
(https://boostjp.github.io/tips/network/tcp.html)
・[Boost.Asio ゲームループで非同期操作を行う]
(https://faithandbrave.hateblo.jp/entry/20110325/1301036991)