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

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 以外の値を返します。