ホーム > デベロッパ > BREW プログラミング入門 > TCP / IP ネットワークプログラミング > - 1 / 3 -

TCP / IP ネットワークプログラミング - 1 / 3 -

お客様のご要望にお応えして、" BREW プログラミング入門 " の連載を再開いたします。

早速 BREW での TCP/IP ネットワークプログラミングから始めます。

BREW ソケットプログラミング

「ソケットプログラミングは、ホスト名とポート番号を指定して接続すれば、あとはデータを送受信するだけ」という認識の方には、少々複雑かもしれません。

何故なら、DNS サーバーへの問い合わせからデータの送受信に至るまで、ほとんどの処理を非同期関数 ( コールバック関数 ) として記述しないといけないからです。

シングルスレッドな環境であるために、BREW プログラミングではいろんな非同期処理 ( 以下の コールバック と同義 ) に出くわしますが、非同期処理の基本的な考え方はソケットプログラミングの場合と同じです。

アプリの概要

最初に、"Push Select Key ..." を表示します。
セレクトキーが押されると、通信が開始します。通信が終了すると、受け取ったデータを表示します。

MIF ファイルの設定

MIF ファイルには「ネットワーク」の特権レベルを設定します。

MIF エディタ

※ 1. MIF ファイルの特権レベルの設定により、アプリからアクセスできる API を明示的に指定することでセキュリティレベルを制御します。適切な特権レベルが設定されていないと、当該インターフェースのインスタンス生成関数 ISHELL_CreateInstance() でエラーが発生します。 通常、アプリ実行に必要最低限の特権レベルを設定します。特権レベルを追加すると QUALCOMM やキャリアで実施される検証で合格に必要なテスト項目が増えます。

※ 2. MIF ファイルの特権レベルと BREW インターフェースの関係

特権レベル BREW インターフェース
ファイル IFileMgr / IFile / IDatabase / IDBMgr / IDBRecord / ISound / ISoundplayer によるローカルファイルへの読み書き
ネットワーク INetMgr / ISocket による TCP / IP ネットワークアクセス
位置情報取得 IPosDet による位置情報取得
TAPI ITAPI による電話機能 ( Telephony Application Programming Interface ) へのアクセス
Web アクセス IWeb による HTTP プロトコルを使った Web アクセス
共用ディレクトリへの
書き込みアクセス
IFileMgr / IFile による共用ディレクトリへの書き込み
ベル音ディレクトリへの
書き込みアクセス
IFileMgr / IFile によるベル音ディレクトリへの書き込み
アドレス帳へのアクセス IAddrBook によるアドレス帳へのアクセス
セクタ情報へのアクセス IPositionDet による携帯電話のセクタ情報へのアクセス
詳細設定 [詳細設定]のボタンを押すと、[ダウンロード]または[すべて]が選択可能です。これらはキャリア・端末メーカー専用の特権レベルです。

ネットワークを使うための準備

ISocket は ソケットプログラミングのためのBREW インターフェースです。

INetMgrは ISocket インターフェースを管理するためのBREW インターフェースです。通常、ISHELL_CreateInstance 関数を使って BREW インターフェースのインスタンスを生成しますが、ISocket インターフェースのインスタンスは INetMgr インターフェースを使って生成します。また、DNS への問い合わせも INetMgr インターフェースを使います。

アプレット構造体には INetMgr / ISocket インターフェースのインスタンス変数、メッセージ送受信バッファ変数、送受信データ量の変数、接続先ホスト IP アドレス用変数、コールバック用変数を追加します。


■アプレット構造体の宣言

// アプレット構造体
typedef struct SocketApp {
    AEEApplet a; // アプレット構造体の先頭メンバは必ず AEEApplet 型にすること。
    Common common; // 画面描画用

    // 通信用
    INetMgr* netmgr;        // INetMgr インターフェースのインスタンス変数
    ISocket* socket;        // ISocket インターフェースのインスタンス変数
    uint16 index;           // 送受信データ量を格納
    AEEDNSResult dnsresult; // 接続先ホストの IP アドレスを格納
    AEECallback callback;   // コールバック関数とその引数を格納
} SocketApp;

■アプレット開始時に呼び出される OnAppStart 関数

static boolean OnAppStart(SocketApp* app)
{
    IShell* shell = app->a.m_pIShell;
    IDisplay* display = app->a.m_pIDisplay;

    app->socket = NULL;
    ISHELL_CreateInstance(shell, AEECLSID_NET, (void**)&app->netmgr);
    // (中略)
    return TRUE;
}

■アプレット終了時に呼び出される OnAppStop 関数

static boolean OnAppStop(NetworkApplet* app)
{
    // 各種解放処理
    if (app->socket != NULL) {
        ISOCKET_Cancel(app->socket, NULL, NULL);
        ISOCKET_Release(app->socket);
    }
    INETMGR_Release(app->netmgr);
    COMMON_Free(&app->common);
    return TRUE;
}

※ その他 : " AEENet.h " ヘッダーファイルのインクルードが必要です。

コールバック

DNS サーバーへの問い合わせは携帯電話側では DNS サーバーからの返答待ちの状態が暫く続く処理です。

このような場合、BREW ではその処理が終了したときに自動的に呼び出される関数を登録します。

コールバック関数登録後、アプリは速やかに現在のイベント処理を完了して BREW に制御を戻し、次のイベントを待ちます。

この仕組みが、所謂「コールバック」です。登録された関数はコールバック関数と呼ばれます。コールバック関数には返答が返ってきた後にする処理を記述します。

コールバック関数を登録する関数は目的によって異なります。

ソケット通信関連の例で言うと、DNS サーバーへの問い合わせはINETMGR_GetHostByName 関数、ホスト接続は ISOCKET_Connect 関数、データ送信は ISOCKET_Writeable 関数、データ受信は ISOCKET_Readable 関数を使います。

ISOCKET_Cancel 関数を呼ぶと、ソケット通信関連のコールバックはキャンセルされます。

※ 1. BREW はイベント駆動型アーキテクチャで、しかもシングルスレッド環境のシステムです。 イベント駆動型モデルでは、イベントが発生するとシステムからアプリにイベントが渡され、 アプリ側でのイベント処理が終了するとシステムに制御が戻ります。 シングルスレッド環境では、アプリ側のイベント処理で待ちなどが発生して時間が掛かる場合は処理を打ち切って次の処理を実行し、 速やかにシステムに制御を戻す方が効率的です。コールバックはこのために考えられた、 シングルスレッド環境のシステムに共通する BREW のメカニズムです。

※ 2. アプリ側のイベント処理が長時間に及ぶと、BREW によってアプリは強制終了させられます。 強制終了までの時間は携帯電話によって異なりますが、だいたい 1 秒程度です。 BREW では、アプリの個々のイベント処理は少なくとも 1 秒以内に終了するようにプログラム設計しなければなりません。

AEECallback 構造体

AEECallback は、コールバック関数とその引数を一つにまとめた構造体で、次のように定義されます。

typedef struct _AEECallback
{
    AEECallback* pNext;
    void*        pmc;
    PFNCBCANCEL  pfnCancel;
    void*        pCancelData;
    PFNNOTIFY    pfnNotify;
    void*        pNotifyData;
    void*        pReserved;
} AEECallback;

AEECallback 構造体への設定はフィールドに直接アクセスするよりも、CALLBACK_Init マクロ関数を使うのが便利です。

    CALLBACK_Init(&pApp->callback, TCPDNSConnect, pApp);

のように第 1 引数を AEECallback 構造体、第 2 引数をコールバック関数、第 3 引数をコールバック関数への引数として、CALLBACK_Init マクロ関数を呼ぶだけで、コールバック関数の登録に必要な情報が AEECallback 構造体に設定されます。