STM32でのHTTPプロトコルの詳細と実装

STM32でのHTTPプロトコルの詳細と実装

HTTPプロトコルとは何か?

HTTP(HyperText Transfer Protocol、ハイパーテキスト転送プロトコル)は、World Wide Web上のサーバーからクライアントブラウザへデータを転送するためのプロトコルです。TCP/IPプロトコルに基づいて動作し、クライアント-サーバーモデルを採用しています。アプリケーション層のプロトコルであり、テキスト、画像、オーディオなど様々なリソースの転送に使用できます。

HTTPプロトコルの特徴:

  • シンプルさ:クライアントがサーバーにリクエストを送信する際には、リクエストメソッドとパスを送信するだけでリソースを取得できます。GET、HEAD、POSTなどのメソッドがあり、それぞれクライアントとサーバー間の通信タイプが異なります。
  • 高速性:HTTPプロトコルのシンプルさにより、HTTPサーバーのプログラムサイズが小さく、通信速度が高速です。
  • 柔軟性:HTTPは任意のデータオブジェクトの転送を許可しており、転送タイプはContent-Typeでマークされます。
  • 接続管理:HTTP 1.1以前は、各リクエストごとにTCP接続を切断する「非接続」方式でした。HTTP 1.1以降では、持続的接続が導入され、不要なTCP接続の確立と切断によるオーバーヘッドが削減されています。
  • 状態保持の欠如:HTTPはステートレスプロトコルであり、前の状態を記憶しません。これにより、後続処理で前の情報が必要な場合はデータを再送する必要があります。この問題を解決するため、Cookie技術が導入されました。

URLとリソース

URL(Uniform Resource Locator、統一資源位置指定子)は、インターネット上の特定のリソースを一意に識別するためのアドレスです。URI(統一資源識別子)はURLとURN(統一資源名)の2つのサブセットから構成されます。

URLの一般的な形式:

<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>

コンポーネント 説明
スキーム サーバーにアクセスする際に使用するプロトコル(HTTP、HTTPS、FTPなど)
ユーザー リソースアクセスに必要なユーザー名
パスワード ユーザー名に続くパスワード認証
ホスト リソースが存在するサーバーのホスト名またはIPアドレス
ポート サーバーがリッスンしているポート番号(HTTPは80、HTTPSは443がデフォルト)
パス サーバー上のリソースのパス
パラメータ 特定のスキームで使用されるパラメータ
クエリ アプリケーションをアクティブ化するためのパラメータ
フラグメント リソースの一部を指す名前(サーバーには送信されない)

HTTPメッセージ

HTTPメッセージは3つの部分で構成されます:

  1. メッセージを記述する「開始行」
  2. 属性を含む「ヘッダー」
  3. オプションの「データ本体」

リクエストメッセージとレスポンスメッセージの開始行の形式が異なります:

HTTPリクエストメッセージ:

<method> <request-URL> <version> // 開始行
<headers> // ヘッダー

<entity-body> // データ本体

HTTPレスポンスメッセージ:

<version> <status> <reason-phrase> // 開始行
<headers> // ヘッダー

<entity-body> // データ本体

HTTPステータスコード

範囲 定義済み範囲 説明
100-199 100-101 情報
200-299 200-206 成功
300-399 300-305 リダイレクト
400-499 400-415 クライアントエラー
500-599 500-505 サーバーエラー

STM32でのHTTP通信の実装

HTTP通信の基本的なフロー:

  1. 接続構造体の作成
  2. ドメイン名のサーバーへの接続(DNS推奨)、デフォルトポート番号を使用
  3. HTTPリクエストメッセージの送信
  4. サーバーの応答を待ち、データを受信

ネットワークデータは非常に大量になる可能性があるため、十分な大きさのバッファを使用してデータを受信する必要があります。

HTTPリクエストの例

GET / HTTP/1.1
Host: www.example.com

STM32での実装例

以下は、FreeRTOS環境でのTCPクライアント実装の例です:

// タスク:HTTP通信処理
void HttpCommunicationTask(void const * argument)
{
    // 変数宣言
    uint8_t txBuffer[128];
    uint16_t dataLength;
    BaseType_t result;
    
    // 無限ループ
    for(;;)
    {
        // HTTPリクエストの準備
        dataLength = PrepareHttpRequest(txBuffer, sizeof(txBuffer));
        
        // TCP接続の確立
        if(TcpConnectToServer("www.example.com", 80) == SUCCESS)
        {
            // データの送信
            result = TcpSendData(txBuffer, dataLength);
            
            if(result == SUCCESS)
            {
                // レスポンスの受信処理
                ProcessHttpResponse();
            }
            
            // 接続のクローズ
            TcpCloseConnection();
        }
        
        // 次の通信までの待機
        osDelay(5000);
    }
}

// HTTPリクエストの準備関数
uint16_t PrepareHttpRequest(uint8_t *buffer, uint16_t bufferSize)
{
    const char *requestTemplate = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n";
    uint16_t length = strlen(requestTemplate);
    
    if(length > bufferSize)
        length = bufferSize;
    
    memcpy(buffer, requestTemplate, length);
    
    return length;
}

この実装では、HTTPリクエストを準備し、TCP接続を確立してデータを送信し、サーバーからの応答を処理します。接続が不要になったらクローズし、一定時間待機して次の通信を準備します。

データ受信処理の最適化

大量のデータを受信する場合、効率的な処理が重要です。以下はデータ受信処理の最適化例です:

// レスポンス受信処理関数
void ProcessHttpResponse(void)
{
    uint8_t rxBuffer[1024];
    uint16_t totalReceived = 0;
    uint16_t chunkSize;
    
    while(totalReceived < MAX_RESPONSE_SIZE)
    {
        // データチャンクの受信
        chunkSize = TcpReceiveData(rxBuffer + totalReceived, sizeof(rxBuffer) - totalReceived);
        
        if(chunkSize == 0)
            break; // 受信データがなくなった
            
        totalReceived += chunkSize;
        
        // 必要に応じて処理
        ProcessDataChunk(rxBuffer + totalReceived - chunkSize, chunkSize);
    }
    
    // 完全なデータの処理
    ProcessCompleteResponse(rxBuffer, totalReceived);
}

このアプローチでは、データチャンクを効率的に受信し、必要に応じて処理します。大きなデータでもメモリ効率良く扱うことができます。

タグ: STM32 HTTP TCP/IP FreeRTOS 嵌入式开发

7月21日 18:18 投稿