前のページ次のページ上に戻るホーム SophiaFramework 2.1

6.6. ネットワーク ストリーム

SFUNetworkStream は、TCP クライアントとしてのネットワーク入出力を実現します。 ストリーム バッファとして内部で SFUNetworkBuffer を使用しています。

[Tip] Tip

BREW のネットワーク機能を使用するときは、 MIF ファイルの設定で、アプレットの [Network] 特権レベル を有効にする必要があります。

ここでは、HTTP を通じて Web サーバーにアクセスする例を取り上げます。

class TestStream {
    SFUNetworkStreamPtr netstream;
    Void NotifyFunc(enum SFUNetworkBuffer::NOTIFICATION);
    static Void _NotifyFunc(enum SFUNetworkBuffer::NOTIFICATION notify, VoidPtr p)
    {((TestStream*)p)->NotifyFunc(notify);}
      
    Void Start();
};

Void TestStream::Start() {
    SFUIPEndpoint endpoint("216.239.39.99:80");
    netstream = new SFUNetworkStream(endpoint, _NotifyFunc, this, 500);
    if (netstream->Exception() != NO_ERROR) {
      return
    }
}
      
Void TestStream::NotifyFunc(enum SFUNetworkBuffer::NOTIFICATION notify)
{
    switch (notify) {
        case SFUNetworkBuffer::NOTIFY_ERROR:
            TRACE("NetworkStream Notify ERROR");
            break;

        case SFUNetworkBuffer::NOTIFY_CONNECT:
            TRACE("NetworkStream Notify CONNECT");
            (*netstream) << "GET /index.html HTTP/1.0" << endl << endl;
            netstream->Flush();
            break;

        case SFUNetworkBuffer::NOTIFY_READ:
            TRACE("NetworkStream Notify READ");
            {
                UInt08 buf[1000];
                UInt08* p = buf;
                UInt08* line = buf;

                TRACE("available %d", netstream->Available());
                while (! netstream->IsEOB() && netstream->Exception() == 0) {
                    (*netstream) >> *(p++);
                }
                *p = '\0';
                TRACE("DATA>>> %s", buf);

                if (! netstream->IsEOS()) {
                    netstream->Fetch(100);
                }
            }
            break;

        case SFUNetworkBuffer::NOTIFY_WRITE:
            TRACE("NetworkStream Notify WRITE");
            netstream->Fetch(100);
            break;
    }
}      

まず TestStream::Start() では、接続先の IP エンドポイントを作成しています。 IP エンドポイントは IP アドレスとポート番号のペアです。 IP エンドポイントは次のように INAddr と INPort から作成することもできます。

INAddr addr;
INET_ATON("216.239.39.99", &addr);
INPort port = HTONS(80);
SFUIPEndpoint endpoint(addr, port);

SFUNetworkStream のコンストラクタでは、 TCP 接続先の IP エンドポイントと、通知を受け取るコールバック関数、 ユーザー定義データ、送信バッファの初期サイズを指定します。 コールバック関数はグローバル関数かクラスの静的メンバ関数でなくてはなりません。

ここではユーザー定義データとして this を渡し、 通知関数として TestStream::_NotifyFunc を指定しています。 TestStream::_NotifyFunc では引数に渡された TestStream オブジェクトの 関数を呼び出すことで通常のメンバ関数に処理を委譲しています。

SFUNetworkStream のコンストラクタではサーバーに対して接続を試みますが、 接続時にエラーが発生すると、 Exception() 関数が NO_ERROR = 0 以外の値を返します。 SFUNetworkStream のコンストラクタが成功すると、 すぐに接続が開始し、接続が完了するとコールバックに通知されます。 接続完了の通知ではコールバックに SFUNetworkBuffer::NOTIFICATION が渡されますので、そのタイミングで追加の処理を行うことができます。

この例では、接続完了後にサーバーに対して HTTP リクエストを送信しています。 データを送信するには、ストリームのインサータを使って ストリーム バッファにデータを蓄積した上で、 Flush() 関数を呼び出します。 実際のデータ送信は Flush() 関数呼び出し時に行われます。

Flush() を呼び出すと、ストリーム バッファに蓄積されたデータが サーバーに送信され、送信が完了すると再びコールバック関数が呼び出されます。 このときの通知コードは SFUNetworkBuffer::NOTIFY_WRITE です。 ここでは Web サーバーに HTTP リクエストを送信した後、 Web サーバーからの応答を受け取るために、Fetch() 関数を呼び出しています。

Fetch() 関数の引数には最大のバッファサイズを指定します。 Fetch() を呼び出すと通知コールバックに SFUNetworkBuffer::NOTIFY_READ が渡されます。 コールバックでは受信バッファのデータを受け取るために エクストラクタで 1 バイトずつ読み取っています。 バッファの終端に達すると IsEOB() が TRUE になります。 また、ストリームの終端まで読み取ると IsEOS() が TRUE になりますので、 ストリームの終端 (HTTP 応答の終端) に達していない場合は、 再び Fetch() 関数を呼び出すことで、 受信処理を繰り返します。

接続、送信、受信の処理中に通信エラーがあると、 コールバック関数に SFUNetworkBuffer::NOTIFY_ERROR が渡されます。 また、ストリームの作成時、書き込み時、読み取り時に何らかのエラーが 発生しますと SFUNetworkStream::Exception() が NO_ERROR = 0 以外の値を返します。