ホーム > デベロッパ > SophiaFramework > BREW C++ 逆引きコード集

BREW C++ プログラミング 逆引きコード集 : ネットワーク通信

C++ で作成されたBREW アプリで、ネットワーク通信を行う方法です。
SophiaFramework を用いています。

HTTP / HTTPS 通信の行う方法

SFXHTTPConnection クラスを利用してHTTP / HTTPS 通信を行います。

// HTTP / HTTPS 通信に必要な SFXHTTPConnection クラスのインスタンス _http は
// クラスのメンバ変数として定義する
class MyClass {
private:
    SFXHTTPConnection _http;
    SFXAnsiStringStreamReader _reader;
    SFXAnsiString _receivedString;
public:
    Void Start(Void);
    CALLBACK_DECLARE_SFXHTTPCONNECTION(OnConnect)
    CALLBACK_DECLARE_SFXANSISTRINGSTREAMREADER(OnFetch)
};

Void MyClass::Start(Void)
{
    SFCError error(SFERR_NO_ERROR);

    // HTTP 接続の初期化を行う
    if ((error = _http.Open()) == SFERR_NO_ERROR) {
    
        // HTTP リクエスト メソッドを "GET" に設定する
        // 設定省略時は "GET" となる
        _http.SetMethod("GET");

        // 接続を開始する
#if 1
        // HTTP 接続の場合
        if ((error = _http.Connect("http://www.example.com/",
                         CALLBACK_FUNCTION(OnConnect))) == SFERR_NO_ERROR) {
#else
        // HTTPS 接続の場合: 
        //     ※ サーバー証明書が使用するCA証明書が携帯端末に標準搭載
        //          されていない場合、CA証明書を追加する必要がある
        //                                     [下記『関連情報』参照]
        //             
        // 必要に応じて検証モードを設定する
        _http.SetTrustMode(SSL_TRUST_MODE_FAIL);
        if ((error = _http.Connect("https://www.example.com/",
                         CALLBACK_FUNCTION(OnConnect))) == SFERR_NO_ERROR) {
#endif
            ...
        }
    }

    if (error != SFERR_NO_ERROR) {
        // エラーが発生したとき
        _http.Close();
    }
    return;
}

// 接続が完了すると呼び出されるコールバック関数
CALLBACK_IMPLEMENT_SFXHTTPCONNECTION(MyClass, OnConnect, error)
{
    SFXPropertyConstPtr header;
    SInt16 i;

    if (error == SFERR_NO_ERROR) {
        
        // 各種パラメータを表示する

        // HTTP ステータス コードを取得する
        TRACE("result code = %d", _http.GetResultCode());
        // HTTP レスポンス ヘッダーの Content-Length フィールドを取得する
        TRACE("content length = %d", _http.GetLength()); 
        // HTTP レスポンス ヘッダーの Content-Type フィールドを取得する
        TRACE("content type = %s", _http.GetType().GetCString());
        // HTTP レスポンス ヘッダーの Content-Encoding フィールドを取得する
        TRACE("content encoding = %s", _http.GetEncoding().GetCString());
        // HTTP レスポンス ヘッダーの Date フィールドを取得する
        TRACE("date = %s", 
              _http.GetDate().Format("YYYY/MM/DD hh:mm:ss").GetCString());
        // HTTP レスポンス ヘッダーの Expires フィールドを取得する
        TRACE("expires = %s", 
              _http.GetExpires().Format("YYYY/MM/DD hh:mm:ss").GetCString());
        // HTTP レスポンス ヘッダーの Last-Modified フィールドを取得する
        TRACE("last modified = %s",
         _http.GetLastModified().Format("YYYY/MM/DD hh:mm:ss").GetCString());

        
        // HTTP レスポンス ヘッダーを取得する
        header = &_http.GetResponseHeader();
        
        // HTTP レスポンス ヘッダーをすべて表示する
        for (i = 0; i < header->GetSize(); ++i) {
            TRACE("%s: %s", header->GetKey(i).GetCString(), 
                  header->GetValue(i).GetCString());
        }

        if (_http.GetResultCode() == 200) {

            // データ受信用ストリームを取得する
            if ((error = _http.GetStreamReader(1024, &_reader))
                == SFERR_NO_ERROR) {

                // フェッチ(データ受信)する
                // データ受信が完了すると、OnFetch 関数に通知される
                if ((error = _reader.Fetch(CALLBACK_FUNCTION(OnFetch)))
                    == SFERR_NO_ERROR) {
                    ...
                }
            }
        }
        else {
            error = SFERR_INVALID_STATE;
        }
    }

    if (error != SFERR_NO_ERROR) {
        // エラーが発生したとき
       _http.Close();
    }
    return;
}

// フェッチ(データ受信)が完了したときに呼び出されるコールバック関数
CALLBACK_IMPLEMENT_SFXANSISTRINGSTREAMREADER(MyClass, OnFetch, error)
{
    SFXAnsiString string;

    if (error == SFERR_NO_ERROR) {

        // データ受信用ストリームからデータを取得する
        if ((error = _reader.ReadSFXAnsiString(&string)) == SFERR_NO_ERROR) {

            // 断片化されたデータを結合する
            if ((error = _receivedString.Add(string)) == SFERR_NO_ERROR) {

                // 残りのデータをチェックする
                if (_reader.Ends()) {

                    // すべてのデータが受信できたので表示する
                    TRACE("--------");
                    TRACE("%s", _receivedString.GetCString());
                    TRACE("--------");

                    // 明示的にリソースを解放する
                    _reader.Release();
                    _http.Close();
                }
                else {

                    // フェッチ(データ受信)する
                    // データ受信が完了すると、OnFetch 関数に通知される
                    error = _reader.Fetch(CALLBACK_FUNCTION(OnFetch));
                }
            }
        }
    }

    if (error != SFERR_NO_ERROR) {
        // エラーが発生したとき
        _reader.Release();
        _http.Close();
    }
    return;
      

独自にルート証明書を追加して https 通信を行う方法

https 通信を行うとき、サーバ証明書が使用するCA証明書が SSLROOTCERTS クラスに含まれない場合、BREW アプリ側で独自にルート証明書を追加する必要があります。

SophiaFramework UNIVERSE では、以下のようにして https 通信を行います。

  1. SFBX509Chain インスタンスを生成します。
  2. SFXFile , SFXPath , SFXBinaryStreamReader , SFXBuffer クラスを使って、DERエンコードされたCA証明書をバイナリデータとして読み込みます。
  3. SFBX509Chain::AddCert 関数を呼び出して、[1] で生成した SFBX509Chain インスタンスにWEBOPT_X509_ROOT_CERTS (ルート認証機関の証明書) として [2] で読み込んだ証明書(バイナリ形式)をセットします。
  4. SFXHTTPConnection::Open 関数を呼び出して https 通信をオープンします。
  5. SFXHTTPConnection::SetTrustMode 関数を呼び出して、認証モードを "SSL_TRUST_MODE_FAIL" に設定します。
  6. SFXHTTPConnection インスタンスが内部に保持する SFBWeb インスタンスを取得します。
  7. SFBWeb::AddOpt 関数を呼び出して、SFBWeb インスタンスにWEBOPT_DEFAULTSとして[1]で生成した SFBX509Chain インスタンスを追加します。
  8. SFXHTTPConnection::Connect 関数を呼び出して、https 接続を行い、以下 https プロトコルでデータ通信を行います。
  9. 最後に、SFXHTTPConnection::Close 関数を呼び出して https 通信をクローズします。

具体的なコードについては、下記のサンプルコードをご覧ください。

サンプルコードダウンロード( httpsapp.zip: 21.3kb )

(注)CA証明書読み込み時のバッファ(  SFXBuffer )および SFBX509Chain インスタンスを明示的に解放する場合は、SFXHTTPConnection::Close 関数呼出し後に行わなければいけません。そのため、CA証明書の読み込みおよび SFBX509Chain インスタンスの生成は、SFXHTTPConnection::Open 関数呼び出し前に行うことを推奨します。
      

BREW 3.1 端末でHTTPS 通信を高速化する方法

QUALCOMM 社の情報によりますと、 BREW3.1.2 以前の実装では、ISSL インターフェースが過剰にパケットを細分化するため HTTPS 通信のパフォーマンスが劣化するらしいです。(参照:関連情報)

この問題を解決するためには、 下記のように SFXHTTPConnection クラスを開いてから接続するまでの間に、 SFXHTTPConnection クラスが内部で保持する SFBWeb インスタンスを取得して、この問題が解決されている ISSL インターフェースのクラス ID「AEECLSID_SSL_101」を渡すようにします。

なお、関連情報には、 『本機能は利用例が少なく、十全な評価がされていないため、使用のリスクは御社でご判断下さい』とあります。

#include "AEESSL_WEBOPT_CLASSID.h"
#include "ISSL.bid"

_http.Open()

SFBWebOpts webopts = SFBWebOpts::NewInstance(&error);
WebOpt opt[2];
opt[0].nId = WEBOPT_SSL_CLASSID;
opt[0].pVal = (VoidPtr)AEECLSID_SSL_101;
opt[1].nId = WEBOPT_END;
opt[1].pVal = null;
webopts->AddOpt(opt);
SFBWebSmp web = _http.GetSFBWeb();
web->AddOpt(opt);

_http.Connect(url, XALLBACK_INTERNAL(OnConnect));

※ 接続時間が短縮されたもののフェッチに時間がかかる場合は、ストリームリーダーのバッファサイズを小さくしてみてください。たとえば、4096バイト(デフォルト)を2048バイトにすることで高速化された例があります。

      

SSL メール受信をする

SFXPOP3Receiver クラスの SFXPOP3Receiver::SetSSLModeSFXPOP3Receiver::SetTrustMode を使って、SSL メール受信を行います。

class MyClass {
private:
    SFXPOP3Receiver _receiver;
    CALLBACK_DECLARE_SFXPOP3RECEIVER(POP3Callback)
public:
    Void Start(Void);
};

// 太字の部分を追加
Void MyClass::Start(Void)
{
    // ユーザー名とパスワードを設定する
    _receiver.SetAccount("user", "password");

    // POP3 サーバーの IP アドレスとポート番号を指定する
    //  ( ドメインは自動解決される )
    _receiver.SetServer(SFXSocketAddress("pop3server.example.com:995"));

   // SSL メール受信の設定
   _receiver.SetSSLMode(true);  // SSL 接続モードの設定
   // 証明書の検証モードの設定
   _receiver.SetTrustMode(SSL_TRUST_MODE_FAIL);   
 
    // メールを受信する。受信が完了すると、POP3Callback 関数が呼び出される
    if ((error = _receiver.Receive(CALLBACK_FUNCTION(POP3Callback)))
        != SFERR_NO_ERROR) {
        // error が SFERR_NO_ERROR でない場合はコールバックが戻らないので、
        // ここでエラー処理をする
    }
}

// メール受信が完了したときに呼び出されるコールバック関数
CALLBACK_IMPLEMENT_SFXPOP3RECEIVER(MyClass, POP3Callback, error)
{
    SInt32 i;

    if (error == SFERR_NO_ERROR) { 
        //受信に成功した場合

        // 受信したメールの配列 ( SFXArray ) を取得する
        const SFXArray<SFXPOP3Receiver::MailInfoPtr>& mailArray =
            receiver.GetReceivedMailArray();

        // メール数を表示する
        TRACE("received %d mails", mailArray.GetSize());

        for (i = 0; i < mailArray.GetSize() ; i++) {
            SFXPOP3Receiver::MailInfoPtr minfo = mailArray[i];

            // 左から順に、メール サイズ、UIDL、メール ヘッダーとメール本文
            // を含む メール メッセージを含むメール本体を表示する
            TRACE("%d, %s, %s", minfo->size, 
                   minfo->uidl.GetCString(), 
                   minfo->mail.GetCString());

        }
    }
}
      

SSL メール送信をする

SFXSMTPSender クラスの SFXSMTPSender::SetSSLModeSFXSMTPSender::SetTrustModeSFXSMTPSender::SetAuthorization を使って、SSL メール送信を行います。

class MyClass {
private:
    SFXSMTPSender _sender;
    CALLBACK_DECLARE_SFXSMTPSENDER(SMTPCallback)
public:
    Void Start(Void);
};

// 太字の部分を追加
Void MyClass::Start(Void)
{
    SFCError error;
    SFXMailMessage message;

    // メール ヘッダーに From フィールドを設定する
    message.SetFromField("fromaddress@example.com");

    // メール ヘッダーに To フィールドを追加する
    message.AddToField("toaddress1@example.com");
    message.AddToField("toaddress2@example.com");

    // メール ヘッダーに Subject フィールドを設定する
    message.SetSubjectField("Mail Subject");

    // メール メッセージの本文を設定する
    message.SetBody("Mail test\r\nThis mail is sent by SFXSMTPSender.\r\n");

    // SMTP サーバーの IP アドレスとポート番号を指定する
    //  ( ドメインは自動解決される )
    _sender.SetServer(SFXSocketAddress("smtpserver.example.com:465"));

    // SSL メール送信の設定
    _sender.SetSSLMode(true);         // SSL 接続モードの設定
    // 証明書の検証モードの設定
    _sender.SetTrustMode(SSL_TRUST_MODE_FAIL);  
    // SMTP 認証モードの設定 
    _sender.SetAuthorization(AUTH_CRAM_MD5,"username","password");  

    // メールを送信する。送信が完了すると SMTPCallback 関数が呼び出される
    if ((error = _sender.SendMessage(&message,
        CALLBACK_FUNCTION(SMTPCallback))) != SFERR_NO_ERROR) {
        // error が SFERR_NO_ERROR でない場合はコールバックが戻らないので、
        // ここでエラー処理をする
    }
}

// メール送信が完了したときに呼び出されるコールバック関数
CALLBACK_IMPLEMENT_SFXSMTPSENDER(MyClass, SMTPCallback, error)
{
    if (error == SFERR_NO_ERROR) {
        TRACE("メールを送信しました。");
    }
    else {
        TRACE("メール送信に失敗しました。 %d", error);
    }
}
      

POP3 メール受信をする

SFXPOP3Receiver クラスを使ってメール受信を行います。

class MyClass {
private:
    SFXPOP3Receiver _receiver;
    CALLBACK_DECLARE_SFXPOP3RECEIVER(POP3Callback)
public:
    Void Start(Void);
};

Void MyClass::Start(Void)
{
    // ユーザー名とパスワードを設定する
    _receiver.SetAccount("user", "password");

    // POP3 サーバーの IP アドレスとポート番号を指定する 
    // ( ドメインは自動解決される )
    _receiver.SetServer(SFXSocketAddress("pop3server.example.com:110"));

    // メールを受信する。受信が完了すると、POP3Callback 関数が呼び出される
    if ((error = _receiver.Receive(CALLBACK_FUNCTION(POP3Callback)))
        != SFERR_NO_ERROR) {
        // error が SFERR_NO_ERROR でない場合はコールバックが戻らないので、
        // ここでエラー処理をする
    }
}

// メール受信が完了したときに呼び出されるコールバック関数
CALLBACK_IMPLEMENT_SFXPOP3RECEIVER(MyClass, POP3Callback, error)
{
    SInt32 i;

    if (error == SFERR_NO_ERROR) { 
        //受信に成功した場合

        // 受信したメールの配列 ( SFXArray ) を取得する
        const SFXArray<SFXPOP3Receiver::MailInfoPtr>& mailArray =
            receiver.GetReceivedMailArray();

        // メール数を表示する
        TRACE("received %d mails", mailArray.GetSize());

        for (i = 0; i < mailArray.GetSize() ; i++) {
            SFXPOP3Receiver::MailInfoPtr minfo = mailArray[i];

            // 左から順に、メール サイズ、UIDL、メール ヘッダーとメール本文を含む
            // メール メッセージを表示する
            TRACE("%d, %s, %s", minfo->size, minfo->uidl.GetCString(), minfo->mail.GetCString());

        }
    }
}
      

SMTP メール送信をする

SFXSMTPSender クラスを使ってメール送信を行います。

class MyClass {
private:
    SFXSMTPSender _sender;
    CALLBACK_DECLARE_SFXSMTPSENDER(SMTPCallback)
public:
    Void Start(Void);
};

Void MyClass::Start(Void)
{
    SFCError error;
    SFXMailMessage message;

    // メール ヘッダーに From フィールドを設定する
    message.SetFromField("fromaddress@example.com");

    // メール ヘッダーに To アドレスを追加する
    message.AddToField("toaddress1@example.com");
    message.AddToField("toaddress2@example.com");

    // メール ヘッダーに Subject フィールドを設定する
    message.SetSubjectField("Mail Subject");

    // メール メッセージの本文を設定する
    message.SetBody("Mail test\r\nThis mail is sent by SFXSMTPSender.\r\n");

    // SMTP サーバーの IP アドレスとポート番号を指定する
    // ( ドメインは自動解決される )
    _sender.SetServer(SFXSocketAddress("smtpserver.example.com:25"));

    // メールを送信する。送信が完了すると SMTPCallback 関数が呼び出される
    if ((error = _sender.SendMessage(&message,
        CALLBACK_FUNCTION(SMTPCallback))) != SFERR_NO_ERROR) {
        // error が SFERR_NO_ERROR でない場合はコールバックが戻らないので、
        // ここでエラー処理をする
    }
}

// メール送信が完了したときに呼び出されるコールバック関数
CALLBACK_IMPLEMENT_SFXSMTPSENDER(MyClass, SMTPCallback, error)
{
    if (error == SFERR_NO_ERROR) {
        TRACE("メールを送信しました。");
    }
    else {
        TRACE("メール送信に失敗しました。 %d", error);
    }
}
      

UDP ソケット通信を行う方法

SFXUDPSocket クラスを利用して UDP ソケット通信を行います。

// UDP ソケット通信に必要な SFXUDPSocket クラスのインスタンス _socket はクラスのメンバ変数として定義する
class MyClass {
private:
    SFXUDPSocket _socket;

public:
    Void Start(Void);

    // コールバック関数
    CALLBACK_DECLARE_SFXUDPSOCKET(OnBind)
    CALLBACK_DECLARE_SFXUDPSOCKET(OnSend)
    CALLBACK_DECLARE_SFXUDPSOCKET(OnReceive)
};

Void MyClass::Start(Void)
{
    SFCError error;

    // ソケットを開く
    if ((error = _socket.Open()) == SFERR_NO_ERROR) {

        // ソケットをローカル の IP アドレスとポート番号にバインドする
        OnBind(SFERR_NO_ERROR);
    
    }
    return;
}

// バインド用のコールバック関数
CALLBACK_IMPLEMENT_SFXUDPSOCKET(MyClass, OnBind, error)
{
    SFXSocketAddress address(SFXInetAddress::LoopbackInetAddress(), 1024);

    // エラーが発生したかどうかチェックする
    if (error == SFERR_NO_ERROR) {

        error = _socket.Bind(address);

        switch (error) {
            case SFERR_NO_ERROR:

                // データを非同期に書き込む
                OnSend(SFERR_NO_ERROR);
                break;
            case AEE_NET_WOULDBLOCK:

                // コールバック関数を登録する
                _socket.ScheduleBind(CALLBACK_FUNCTION(OnBind));
                break;
        }
    }
    return;
}

// 送信用のコールバック関数
CALLBACK_IMPLEMENT_SFXUDPSOCKET(MyClass, OnSend, error)
{
    static ACharConst data[] = "udp!";
    SFXSocketAddress address(SFXInetAddress::LoopbackInetAddress(), 1024);
    UInt32 size;

    // エラーが発生したかどうかチェックする
    if (error == SFERR_NO_ERROR) {
        size = sizeof(data) - 1;

        // データを非同期的に送信する
        error = _socket.Send(address, data, &size);

        switch (error) {
            case SFERR_NO_ERROR:

                // 指定したサイズのデータが書き込まれたかチェックする
                // Send 関数は指定したサイズのデータを
                // 一度に書き込めないことがある
                // その場合、ここでは簡易化のためエラーとしている
                if (size == sizeof(data) - 1) {

                    // データを非同期に読み込む
                    OnReceive(SFERR_NO_ERROR);
                }
                else {
                    TRACE("...send failed...");
                }
                break;
            case AEE_NET_WOULDBLOCK:

                // コールバック関数を登録する
                _socket.ScheduleSend(CALLBACK_FUNCTION(OnSend));
                break;
        }
    }
    return;
}

// 受信用のコールバック関数
CALLBACK_IMPLEMENT_SFXUDPSOCKET(MyClass, OnReceive, error)
{
    SFXSocketAddress socket;
    SFXBuffer buffer;
    UInt32 size;

    // エラーが発生したかどうかチェックする
    if (error == SFERR_NO_ERROR) {
        buffer.SetSize(4);

        size = static_cast(buffer.GetSize());

        // 非同期的にデータを受信する
        switch (_socket.Receive(&socket, buffer.GetBuffer(), &size)) {
            case SFERR_NO_ERROR:

                // 指定したサイズのデータが読み込まれたかチェックする
                // Receive 関数は指定したサイズのデータを
                // 一度に読み込めないことがある
                // その場合、ここでは簡易化のためエラーとしている
                if (size == buffer.GetSize()) {

                    // 読み込んだデータを表示する
                    buffer.SetSize(buffer.GetSize() + 1);
                    buffer[buffer.GetSize() - 1] = '\0';
                    TRACE(":%s", SFXAnsiString(buffer).GetCString());

                    // ソケットを閉じる
                    _socket.Close();
                }
                else {
                    TRACE("...receive failed...");
                }
                break;
            case AEE_NET_WOULDBLOCK:

                // コールバック関数を登録する
                _socket.ScheduleReceive(CALLBACK_FUNCTION(OnReceive));
                break;
        }
    }
    return;
}
      

SSL ソケット通信を行う方法

SFXSSLSocket クラスを利用して SSL ソケット通信を行います。

// SSL ソケット通信に必要な SFXSSLSocket クラスのインスタンス _socket はクラスのメンバ変数として定義する
class MyClass {
private:
    SFXSSLSocket_socket;
    SFXAnsiStringStreamWriter _writer; // データ送信用ストリーム
    SFXAnsiStringStreamReader _reader; // データ受信用トリーム

public:
    Void Start(Void);

    // コールバック関数
    CALLBACK_DECLARE_SFXSSLSOCKET(OnConnect)
    CALLBACK_DECLARE_SFXSSLSOCKET(OnNegotiate)
    CALLBACK_DECLARE_SFXANSISTRINGSTREAMWRITER(OnFlush)
    CALLBACK_DECLARE_SFXANSISTRINGSTREAMREADER(OnFetch)
};

Void MyClass::Start(Void)
{
    SFCError error;
    SFXSocketAddress host("www.example.com:995");

    // TCP サーバーとの接続を初期化する
    if ((error = _socket.Open()) == SFERR_NO_ERROR) {
 
        // ホスト名は自動的に解決される
        // TCP サーバーに接続する
        error = _socket.Connect(host, CALLBACK_FUNCTION(OnConnect));
    }
    if (error != SFERR_NO_ERROR) { 
        // エラーが発生したとき
        _socket.Close();
    }
    return;
}

// 接続が確立したときに呼び出されるコールバック関数
CALLBACK_IMPLEMENT_SFXSSLSOCKET(MyClass, OnConnect, error)
{
    if (error == SFERR_NO_ERROR) { 
        // エラーが発生していないとき
        // ネゴシエートする
        error = _socket.Negotiate(CALLBACK_FUNCTION(OnNegotiate));
    }
    if (error != SFERR_NO_ERROR) { 
        // エラーが発生したとき
        _socket.Close();
    }
    return;
}

// ネゴシエートが完了したときに呼び出されるコールバック関数
CALLBACK_IMPLEMENT_SFXSSLSOCKET(MyClass, OnNegotiate, error)
{
    static AChar sendingMessage[] = "GET / HTTP/1.0\r\n\r\n";

    if (error == SFERR_NO_ERROR) {

        // データ送信用ストリームを取得する ( バッファ サイズは 1024 )
        if ((error = _socket.GetStreamWriter(1024, &_writer))
            == SFERR_NO_ERROR) {

            // データを書き込む
            if ((error = _writer.Write(sendingMessage,
                   lengthof(sendingMessage))) == SFERR_NO_ERROR) {

                // フラッシュする(実際にデータを送信する)
                // 送信が完了すると、OnFlush 関数が呼び出される
                error = _writer.Flush(CALLBACK_FUNCTION(OnFlush));
            }
            if (error != SFERR_NO_ERROR) { 
                // エラーが発生したとき
                 _writer.Release();
            }
        }
    }
    if (error != SFERR_NO_ERROR) { 
       // エラーが発生したとき
       _socket.Close();
    }
    return;
}

// フラッシュ ( データ送信 ) が完了したときに呼び出されるコールバック関数
CALLBACK_IMPLEMENT_SFXANSISTRINGSTREAMWRITER(MyClass, OnFlush, error)
{
    // 送信が終わったのでデータ送信用ストリームを解放する
    _writer.Release();

    if (error == SFERR_NO_ERROR) {

        // データ受信用ストリームを取得する ( バッファ サイズは 1024 )
        if ((error = _socket.GetStreamReader(1024, &_reader))
            == SFERR_NO_ERROR) {

            // フェッチ(データ受信)する
            // データ受信が完了すると、OnFetch 関数に通知される
            if ((error = _reader.Fetch(CALLBACK_FUNCTION(OnFetch)))
                != SFERR_NO_ERROR) {
                // エラーが発生したとき
               _reader.Release(); 
            }
        }
    }
    if (error != SFERR_NO_ERROR) { 
        // エラーが発生したとき
        _socket.Close();
    }
    return;
}

// フェッチ(データ受信)が完了したときに呼び出されるコールバック関数
CALLBACK_IMPLEMENT_SFXANSISTRINGSTREAMREADER(MyClass, OnFetch, error)
{
    SFXAnsiString receivedString;

    if (error == SFERR_NO_ERROR) {

        // バッファからデータを receivedString 変数に読み込む
        _reader >> receivedString;

        // 応答を表示する
        TRACE("%s", receivedString.GetCString());
    }
    // 受信が終わったのでデータ受信用ストリームを解放する
    _reader.Release();

    // ソケットを閉じる
    _socket.Close();
    return;
}

※ 日本ベリサイン社の ssltest7.verisign.co.jp:443 または rollovertest2.verisign.co.jp:443 のサーバーにて SSL 接続テストが利用可能です。

      

TCP ソケット通信を行う方法

SFXTCPSocket クラスを利用して、TCP ソケット通信を行います。

// TCP ソケット 通信に必要な SFXTCPSocket クラスのインスタンス _tcp はクラスのメンバ変数として定義する
class NetworkTime {
private:
    SFXTCPSocket _tcp;
    SFXBinaryStreamReader _reader;

public:
    Void Start(Void); // NTP サーバーとの接続を開始する
    Void Stop(Void);  // 接続途中で NTP サーバーとの接続を終了する
    
    // コールバック関数の宣言
    CALLBACK_DECLARE_SFXTCPSOCKET(OnConnect)
    CALLBACK_DECLARE_SFXBINARYSTREAMREADER(OnFetch)
};

// NTP サーバーとの接続を開始する
Void NetworkTime::Start(Void)
{
    SFCError error(SFERR_NO_ERROR);
    // NTP サーバーのアドレスを設定する
    SFXSocketAddress address("www.example.com:37");

    // NTP サーバーとの接続を初期化する
    if ((error = _tcp.Open()) == SFERR_NO_ERROR) {

        // NTP サーバーに接続する
        if ((error = _tcp.Connect(address,
                CALLBACK_FUNCTION(OnConnect))) == SFERR_NO_ERROR) {
            ...
        }
        else {
            // エラーが発生したとき
            _tcp.Close();
        }
    }
	
    if (error != SFERR_NO_ERROR) { 
        // エラーが発生したとき
        // エラー処理
        ...
    }
    return;
}

// 接続途中で NTP サーバーとの接続を終了する場合に呼び出す
Void NetworkTime::Stop(Void)
{
    // 終了処理
    _reader.Release();
    _tcp.Close();
    return;
}

// 接続が確立したときに呼び出されるコールバック関数
CALLBACK_IMPLEMENT_SFXTCPSOCKET(NetworkTime, OnConnect, error)
{
    if (error == SFERR_NO_ERROR) {

        // データ受信用ストリームを取得する
        if ((error = _tcp.GetStreamReader(64, &_reader)) == SFERR_NO_ERROR) {

            // フェッチ(データ受信)する
            // 4 バイトのデータを受信すると、OnFetch 関数に通知される
            if ((error = _reader.Fetch(4, CALLBACK_FUNCTION(OnFetch)))
                == SFERR_NO_ERROR) {
                ...
            }
            if (error != SFERR_NO_ERROR) { 
                // エラーが発生したとき
                _reader.Release();
            }
        }
    }
	
    if (error != SFERR_NO_ERROR) {  
        // エラーが発生したとき
        _tcp.Close();
    }
    return;
}

// フェッチ(データ受信)が完了したときに呼び出されるコールバック関数
CALLBACK_IMPLEMENT_SFXBINARYSTREAMREADER(NetworkTime, OnFetch, error)
{
    SFXDate date; // 日付クラス
    UInt32 time;

    if (error == SFERR_NO_ERROR) {

        // データをビッグ エンディアンとして読み込む設定をする
        _reader.SetEndian(SFXBinaryStreamReader::ENDIAN_BIG);
        
        // データを UInt32 型として読み込み、time 変数に格納する
        if ((error = _reader.ReadUInt32(&time)) == SFERR_NO_ERROR) {
            
            // 日付クラスに取得した時刻 ( 秒 ) を設定する
            date.Set(time);
            
            // 受信したデータは 1900 年 1 月 1 日 からの時刻なので調整する
            date -= SFXDateDuration::Offset19000101();
            
            // 時刻をローカル時刻に変換する
            date += SFXDateDuration::LocalTimeOffset();

            // 時刻を書式に合わせて出力する
            TRACE("%s", date.Format("YYYY/MM/DD hh:mm:ss").GetCString());
        }
    }
	
    if (error != SFERR_NO_ERROR) {
        // エラーが発生したとき
        // エラー処理
        ...
    }

    // 終了処理
    _reader.Release();
    _tcp.Close();
    return;
}
      

URL の2バイト文字をデコードする

URL の2バイト文字をデコードするには、SFBWebUtil::UrlDecode 関数を使用します。

SFXAnsiString str("http%3A%2F%2Fwww.example.com%2F%82Q"
                  "%83o%83C%83g%95%B6%8E%9A%97%F1");     // 変換前文字列
SFXAnsiString ret;                 // 変換後文字列
SInt32 insize = str.GetLength();   // 変換前文字列サイズ
SInt32 outsize;                    // 変換後文字列サイズ

SFBWebUtilSmp webutil = SFBWebUtil::NewInstance();
if (webutil != null) {

    // 変換後文字列のサイズ測定

    webutil->UrlDecode(str.GetCString(), &insize, null, &outsize);
    if (insize == str.GetLength()) {

        // サイズを設定する

        ret.SetLength(outsize);

        // 変換する

        webutil->UrlDecode(str.GetCString(), &insize, ret.GetBuffer(), &outsize);
        
        // ret に結果が格納される
    }
}

参照 SFBWebUtil::NewInstance | SFBWebUtil::UrlDecode | SFXAnsiString::GetLength
SFXAnsiString::GetCString | SFXAnsiString::GetBuffer

      

URL の2バイト文字をエンコードする

URL の2バイト文字をエンコードするには、SFBWebUtil::UrlEncode 関数を使用します。

SFXAnsiString str("http://www.example.com/2バイト文字列"); // 変換前文字列
SFXAnsiString ret;                 // 変換後文字列
SInt32 insize = str.GetLength();   // 変換前文字列サイズ
SInt32 outsize;                    // 変換後文字列サイズ

SFBWebUtilSmp webutil = SFBWebUtil::NewInstance();
if (webutil != null) {

    // 変換後文字列のサイズ測定

    webutil->UrlEncode(str.GetCString(), &insize, null, &outsize);
    if (insize == str.GetLength()) {
    
        // サイズを設定する

        ret.SetLength(outsize);

        // 変換する

        webutil->UrlEncode(str.GetCString(), &insize, ret.GetBuffer(), &outsize);
    }
}

参照 SFBWebUtil::NewInstance | SFBWebUtil::UrlEncode | SFXAnsiString::GetLength
SFXAnsiString::GetCString | SFXAnsiString::GetBuffer

      

ホスト名からIPアドレスを取得する

バージョン 4.0 以降

ホスト名からIPアドレスを取得するには SFXSocketAddress クラスの SFXSocketAddress::Resolve 関数を使用します。
この関数が呼び出されるとネットワーク通信を行い、通信完了後にコールバックとして
登録された関数が呼び出されます。

SFMTYPEDEFCLASS(MyClass)
class MyClass {
private:
    SFXSocketAddress _address;
public:
    Void Function(Void);
    CALLBACK_DECLARE_SFXSOCKETADDRESS(ResolveCallback)
};

Void MyClass::Function(Void)
{
    _address.Set("www.example.com:80");
    
    // ホスト名を解決する (要エラーチェック)
    _address.Resolve(CALLBACK_FUNCTION(ResolveCallback));
}

// ホスト名が解決できたときに呼び出されるコールバック
CALLBACK_IMPLEMENT_SFXSOCKETADDRESS(MyClass, ResolveCallback, error)
{
    SInt32 i;
    for (i = 0; i < _address.GetCount(); ++i) {
        SFXAnsiString string = _address.GetIP(i); // IP アドレスを文字列として取得
    }
}

バージョン 3.0

ホスト名からIPアドレスを取得するには SFUHostResolver クラスを使用します。
この関数が呼び出されるとネットワーク通信を行い、通信完了後にコールバックとして
登録された関数が呼び出されます。

SFMTYPEDEFCLASS(MyClass)
class MyClass {
private:
    SFUHostResolverPtr _resolver;
public:
    Void Function(Void);
    static Void NotifyResolvingSHP(SFCError error, SFUHostResolverRef resolver, 
                               VoidPtr data);
    Void NotifyResolving(SFCError error, SFUHostResolverRef resolver);
};

Void MyClass::Function(Void)  // この関数の中でIPアドレスを取得する
{
    // コンストラクタでコールバック関数を取得
    _resolver = new SFUHostResolver(NotifyResolvingSHP, this);
    // ホスト名を解決 (要エラーチェック)
    _resolver->Resolve("www.example.com");
}

// ホスト名が解決できたときに呼び出されるコールバック
static Void MyClass::NotifyResolvingSHP(SFCError error, SFUHostResolverRef resolver, 
                               VoidPtr data)
{
    static_cast(data)->NotifyResolving(error, resolver);
}

// コールバックの実装
Void MyClass::NotifyResolving(SFCError error, SFUHostResolverRef resolver)
{
    SInt32 i;
    // GetResolvedCount 関数で取得したIPアドレスの個数を取得
    for (i = 0; i < resolver.GetResolvedCount(); ++i) {
        // GetResolvedAddress でIPアドレスを取得し、SFUIPEndpoint 型に変換
        SFUIPEndpoint address(resolver.GetResolvedAddress(i));

    }
    delete &resolver;
}

参照 SFXSocketAddress::Set | SFXSocketAddress::Resolve |
SFXSocketAddress::GetCount | SFXSocketAddress::GetIP

      

自身のIPアドレスを取得する

バージョン 4.0 以降

SFXInetAddress address;

address = SFXInetAddress::LocalInetAddress();

バージョン 3.0

SFBNetMgrSmp netmgr = SFBNetMgr::NewInstance();

INAddr myAddr = netmgr->GetMyIPAddr();    //自分自身のアドレスを取得する

SFUIPEndpoint myEndpoint(myAddr);    // SFUIPEndpoint 型に変換する

参照 SFBNetMgr::NewInstance | SFBNetMgr::GetMyIPAddr