Arudino UNO R4 WiFiをサーバにする・その3/『ナンチャッテWebサーバ』を作る

Arduino

今度はWebサーバを作る

概要

では、Arduino UNO R4 WiFiをWebサーバにしてみましょう。前回の『オウム返しサーバ』ができていれば、むしろ簡単です。

以前、Arduino UNO R3+ESP-WROOM-02Uで実験したときと同様、Webサーバとしては極限まで簡単な仕様にします。

  • 一般のWebサーバと同じく、TCP80番ポートで待ち受けする
  • 対応するメソッドはGETのみ
  • というか、リクエストの内容に関わらず、リクエストを送信してきたクライアントに対して固定のHTMLドキュメントをレスポンスとして送信する
  • レスポンスを送信したらTCP切断

です。HTMLドキュメントのレスポンスを求めないタイプのリクエストが来てもHTMLドキュメントを返してしまうという『なんちゃってWebサーバ』です。

スケッチ

C++
#include "WiFiS3.h"

// 無線LAN接続情報は別ファイルに移した
#include "arduino_secrets.h"
char ssid[] = _SSID;
char pass[] = _PASS;

// リスンポートを80番としてサーバのインスタンスを作成
WiFiServer server(80);

void setup(){
  // シリアルインターフェイスの初期化
  Serial.begin(9600);
  delay(1000);

  // WiFiモジュールの存在確認
  if(WiFi.status() == WL_NO_MODULE){
    Serial.println("WiFiモジュールがありません");
    while(true);
  }

  // WiFiファームウェアバージョンの確認
  String fv = WiFi.firmwareVersion();
  if(fv < WIFI_FIRMWARE_LATEST_VERSION){
    Serial.println("ファームウェアが最新のものではありません");
  }

  // IPアドレスの指定
  IPAddress serverIP(192,168,0,101);
  WiFi.config(serverIP);

  // 無線LANへの接続
  Serial.print("接続中...");
  while(true){
    if(WiFi.begin(ssid, pass) == WL_CONNECTED)break;
    Serial.print(".");
    delay(1000);
  }
  Serial.println("完了");

  // Arduinoに割り当てられたIPアドレスの確認
  Serial.print("IPアドレス:");
  Serial.println(WiFi.localIP().toString());

  // サーバの起動
  server.begin();
}

void loop(){
  WiFiClient client = server.available();
  if(client){
    // クライアントと接続した時の処理
    String currentLine;
    while(true){
      // 1行入力
      currentLine = "";
      while(true){
        if(!client.connected()){
          currentLine = "";
          break;
        }
        if(client.available()){
          // 受信した文字がある場合
          char c = client.read();
          if(c == '\n'){
            break;
          }
          if(c != '\r'){
            currentLine += c;
          }
        }
      }
      if(currentLine == ""){
        // 空行を受診したら受信終了
        break;
      }
    }
    String responseBody = "";
    responseBody += "<!DOCTYPE html>\r\n";
    responseBody += "<html><head><title>test page</title></head>\r\n";
    responseBody += "<body>\r\n";
    responseBody += "<h1>Arduino UNO R4 WiFi</h1>\r\n";
    responseBody += "this is test page.\r\n";
    responseBody += "</body></html>\r\n";
    String responseHeader = "";
    responseHeader += "HTTP/1.0 200 ok\r\n";
    responseHeader += "Content-type: text/html\r\n";
    responseHeader += "Content-length: " + String(responseBody.length()) + "\r\n";
    responseHeader += "\r\n";
    client.print(responseHeader);
    client.print(responseBody);
    client.stop();
    while(client.connected());
  }
}

プログラム解説

内容はかなりオウム返しサーバと共通しているので、違う点のみ解説します。

IPアドレスを設定する
C++
  // IPアドレスの指定
  IPAddress serverIP(192,168,0,101);
  WiFi.config(serverIP);

今回は、ArduinoのIPアドレスをDHCPから取得するのではなく、きまったアドレスを設定するようにしました。きまったIPアドレスを設定するにはWiFi.config()関数を使用します。

書式
C++
void WiFi.config(IPAddress& ipaddress)
引数
名前意味
ipaddressIPAddress&このデバイスに設定するIPアドレス

この引数はIPAddress型です。IPAddress型のインスタンスを生成するには、IPv4アドレスを指定します。

書式
C++
IPAddress インスタンス名(first_octet, second_octet, third_octet, forth_octet)
引数
名前意味
first_octetuint8_tIPv4アドレスの第1オクテットの値
second_octetuint8_tIPv4アドレスの第2オクテットの値
third_octetuint8_tIPv4アドレスの第3オクテットの値
forth_octetuint8_tIPv4アドレスの第4オクテットの値

IPv4アドレスの第1~第4オクテットをそれぞれ引数として与えます。

間違えやすいのですが、

C++
  IPAddress serverIP(192, 168, 0, 101);

このコンストラクタの引数部分は4つの数値をカンマ区切りで記述します。IPv4アドレスの表記につられてドット区切りで書いてしまわないように気をつけてください。

なお、学校の校内LANなどに接続する際には、そのIPアドレスが使用可能かどうかをネットワークの管理者にちゃんと確認してから実験してください。

loop()関数内

オウム返しサーバとだいたい同じです。オウム返しサーバでは”exit”で終了していましたが、HTTPのリクエストはヘッダの最後に必ず空行があるので『空行を受信したらループ脱出』し、HTMLドキュメントを送信してから通信終了としています。

C++
    String responseBody = "";
    responseBody += "<!DOCTYPE html>\r\n";
    responseBody += "<html><head><title>test page</title></head>\r\n";
    responseBody += "<body>\r\n";
    responseBody += "<h1>Arduino UNO R4 WiFi</h1>\r\n";
    responseBody += "this is test page.\r\n";
    responseBody += "</body></html>\r\n";
    String responseHeader = "";
    responseHeader += "HTTP/1.0 200 ok\r\n";
    responseHeader += "Content-type: text/html\r\n";
    responseHeader += "Content-length: " + String(responseBody.length()) + "\r\n";
    responseHeader += "\r\n";
    client.print(responseHeader);
    client.print(responseBody);
    client.stop();
    while(client.connected());

HTMLドキュメントを送出する部分はこのようになっています。

クライアントに送出される文字列は以下の通りです。

HTML
HTTP/1.0 200 ok
Content-type: text/html
Content-length: 134

<!DOCTYPE html>
<html><head><title>test page</title></head>
<body>
<h1>Arduino UNO R4 WiFi</h1>
this is test page.
</body></html>

httpでは、レスポンスとして送出する文字列のうち、最初に現れる空行(この例では3行目)より上(1~3行目)をレスポンスヘッダ、空行より下(5~10行目)をレスポンスボディといいます。

レスポンスボディは、見ての通りHTMLドキュメントそのものです。このプログラムでは固定の内容を変数responseBodyにセットしています。

ステータス行
HTTP/1.0 200 ok

レスポンスヘッダのうち、1行目をステータス行といい、必須です。『200』の部分を応答状態コードといい、3桁の数値で表されます。『200』は『リクエストが成功した』(クライアントから要求されたコンテンツが正常に送信された)ことを表します。今回はリクエスト内容と無関係にHTMLドキュメントを送りつけるという簡易すぎる仕様なので、固定で200を送信しています。

レスポンスヘッダフィールド

2~3行目はレスポンスヘッダフィールドといい、レスポンスボディで送信するドキュメントに関する情報を記述します。フィールドには多くの種類があるのですが、最低限ここに挙げる2つはないとクライアント側が正常に処理できないことがあります。

Content-type: text/html

Content-Typeフィールドは、送信するドキュメントの種類です。ここではHTML文書を表す”text/html”としています。

Content-length: 134

Content-lengthフィールドは、送信するドキュメントの長さ(バイト数)です。responseBody.length()の値を挿入しています。正確にはlength()はバイト数ではなく文字数を求める関数なのですが、今回はHTMLドキュメント内に半角文字しかないので問題ありません。

実行

サーバを起動して、ブラウザのアドレス欄にサーバのアドレス(サンプルソースの通りなら 192.168.0.101)を入力すると、このようにサンプルページが表示されます。

まとめ

  • Webサーバは、クライアントからのリクエストに応じてHTMLドキュメントなどを返す

コメント

タイトルとURLをコピーしました