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

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

SFUNetworkStream は、TCP クライアント ソケット、 UDP ソケットとしてのネットワーク入出力を実現します。

[Tip] Tip

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

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

SFMTYPEDEFCLASS(TestStream)
class TestStream {
private:
    SFUNetworkStream    _net;

public:
    TestStream(Void);
    ~TestStream(Void);
    Void Start(Void);

private:
    static Void OnNotifyEntry(SFUNetworkStream::NotifyEnum notify, SFCError error, VoidPtr data)     
    { TestStreamPtr(data)->OnNotify(notify, error); }
    Void OnNotify(SFUNetworkStream::NotifyEnum notify, SFCError error);
};


Void TestStream::Start() 
{
    SFUIPEndpoint endpoint("216.239.39.99:80");
    
    _net.SetWriteBufferSize(256);
    _net.SetReadBufferSize(4096);

    _net.Open(endpoint, AEE_SOCK_STREAM, OnNotifyEntry, this);
    if (_net.Exception() != NO_ERROR) {
      return;
    }
}
      
Void TestStream::OnNotify(SFUNetworkStream::NotifyEnum notify, SFCError error)
{
    switch (notify) {

        case SFUNetworkStream::NOTIFY_CONNECT:      // 接続が成功/失敗した場合
            TRACE(">> NOTIFY_CONNECT");
            if (error == SFERR_NO_ERROR) {
                _net << "GET /index.html HTTP/1.0" << endl << endl;
                _net.Flush();
            }
            break;

        case SFUNetworkStream::NOTIFY_READ:         // 受信が成功/失敗した場合
            TRACE(">> NOTIFY_READ");
            if (error == SFERR_NO_ERROR) {
                UInt32 availSize = _net.Available();
                BytePtr buf = new Byte[availSize];
                if (buf != NULL) {
                    _net.Get(buf, availSize);
                    TRACE("DATA>>> %s", buf);
                }
                delete[] buf;

                if (_net.IsFetchable()) {
                    _net.Fetch();
                }
            }
            break;

        case SFUNetworkBuffer::NOTIFY_WRITE:        // 送信が成功/失敗した場合
            TRACE(">> NOTIFY_WRITE");
            _net.Fetch();
            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::Open TCP 接続先の IP エンドポイントと、通知を受け取るコールバック関数、 ユーザー定義データを指定します。 コールバック関数はグローバル関数かクラスの静的メンバ関数でなくてはなりません。

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

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

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

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

Fetch を呼び出すと、通知コールバックに SFUNetworkStream::NOTIFY_READ が渡されます。 コールバックでは受信バッファのデータをすべて読み取っています。

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