SFML にはシンプルな HTTPクライアントのクラスがあって、ウェブサーバーにアクセスできます。
「シンプル」つまり、HTTP の基本的な機能を網羅しています(
POST、GET、HEADといったリクエスト。ヘッダー情報へのアクセス。ページボディの読み込みおよび書き込み)。
もっと高機能なこと(HTTPSなど)が必要ならば、専用のHTTPライブラリをオススメします(libcurl、cpp-netlib など)。
でも、単にウェブサーバーとやりとりをするだけなら、SFML で充分なはずです。
sf::Http というクラスを使って HTTP サーバーにアクセスします。
#include <SFML/Network.hpp>
sf::Http http;
http.setHost("http://www.some-server.org/");
// または、こう書く
sf::Http http("http://www.some-server.org/");
上のサンプルでは、接続先のホストをセットしているだけです。まだ、実際にはアクセスしてません。
実際のアクセスは、リクエストを行うときに随時行われます。
あとはリクエストを送信するだけです。基本的にはそれだけです。
sf::Http::Request request;
/*
リクエストの内容を設定...
*/
// レスポンスを受け取る
sf::Http::Response response = http.sendRequest(request);
ウェブサーバーへのリクエストは
sf::Http::Request クラスに設定します。
設定する内容は下記の通り。
- リクエストメソッド: POST (データを送信), GET (ページを取得), HEAD (ヘッダーだけ取得)
- URI: アクセスするページ(または画像などのリソース)。設定したホストからの相対アドレスです。
- HTTP バージョン:デフォルトでは 1.0 です。必要なら変更のこと。
- ヘッダー: キーと値の組み合わせです。
- ボディ:POSTのときだけ使います
sf::Http::Request request;
request.setMethod(sf::Http::Request::Post);
request.setUri("/page.html");
request.setHttpVersion(1, 1); // HTTP 1.1
request.setField("From", "me");
request.setField("Content-Type", "application/x-www-form-urlencoded");
request.setBody("para1=value1¶m2=value2");
sf::Http::Response response = http.sendRequest(request);
最低限必要なヘッダー情報(Host、Content-Length など)は SFML が自動的に設定してくれます。
心配しないでお任せするとよいです。
sf::Http クラスがホストへの接続とリクエストの送信に成功すると、レスポンスが返ってきます。
レスポンスは
sf::Http::Response クラスのインスタンスとして取得されます。
中身は下記の通り。
- ステータスコード。リクエストがサーバーでどう処理されたかを表しています(OK、リダイレクト、NOT FOUND、など)
- サーバーの HTTPバージョン
- ヘッダー情報。キーと値の組み合わせ。
- ボディ
sf::Http::Response response = http.sendRequest(request);
std::cout << "status: " << response.getStatus() << std::endl;
std::cout << "HTTP version: " << response.getMajorHttpVersion() << "." << response.getMinorHttpVersion() << std::endl;
std::cout << "Content-Type header:" << response.getField("Content-Type") << std::endl;
std::cout << "body: " << response.getBody() << std::endl;
ステータスコードは、リクエストが正常に処理されたかどうかの指標です。
200台なら OK。300台はリダイレクトされたという意味。400台はクライアント側のエラー。500台はサーバー側のエラー。
1000台は SFML 特有のエラーです(HTTP の標準仕様には含まれてません)。
ありそうなシチュエーションのサンプルです。
ゲームのスコアをオンラインサーバーに送信します。
#include <SFML/Network.hpp>
#include <sstream>
void sendScore(int score, const std::string& name)
{
// リクエストを準備。
sf::Http::Request request("/send-score.php", sf::Http::Request::Post);
// 名前とスコアを入力
std::ostringstream stream;
stream << "name=" << name << "&score=" << score;
request.setBody(stream.str());
// リクエストを送信
sf::Http http("http://www.myserver.com/");
sf::Http::Response response = http.sendRequest(request);
// ステータスコードを確認。
if (response.getStatus() == sf::Http::Response::Ok)
{
// レスポンスを表示
std::cout << response.getBody() << std::endl;
}
else
{
// エラーがあったようです。
std::cout << "request failed" << std::endl;
}
}
あくまでサンプルとしての単純なやり方です。
プロテクトをかけてないので、簡単に嘘データを送信できてしまいます。
それを防ぐには、リクエストがプログラムから送信されたことを保証するハッシュコードのような、何か別のパラメータが必要になります。
ですが、それは、このチュートリアルの範囲を超えてしまうので触れません。
では最後に、上記のリクエストを受け取ってサーバー側ではどう処理するのか?
PHP で書くなら、こんな感じでしょうか。
<?php
$name = $_POST['name'];
$score = $_POST['score'];
// PHP のチュートリアルじゃないので、詳しくは他の人に訊いてね!
if (write_to_database($name, $score))
{
echo "名前とスコアをデータベースに追加しました!";
}
else
{
echo "データベースへの書き込み失敗……";
}
?>