ラベル Comet の投稿を表示しています。 すべての投稿を表示
ラベル Comet の投稿を表示しています。 すべての投稿を表示

2011-04-21

GWTでChannelAPIクライアントを実装する

昨日に引き続いて、Channel APIの話題です。ライブラリを使って意外と簡単にGWTで実装できましたので、取り急ぎ報告します。あ、まだGAE上では試してません。

gwt-gae-channelライブラリを使う
gwt-gae-channelプロジェクトというのがありますので、これを使いました。まだバージョン0.3αですがいちおう動くようです。なお、gwt.xmlファイルへの記述は、
  • <inherits name='com.google.gwt.appengine.channel.Channel' />
となります。
Tokenの入手
これは、前回の記事を参考にして、まずはTokenを入手してください。入手方法はお好きなように、、、まあ、GWTユーザならGWT-RPCを使うのが普通でしょう。
Channelの接続
ここで、gwt-gae-channelのライブラリを使います。以下のような記述でOK。
ChannelFactory.createChannel(token, new ChannelCreatedCallback() {
            @Override
            public void onChannelCreated(Channel channel) {
                channel.open(new SocketListener() {
                    @Override
                    public void onOpen() {
                        Window.alert("Channel opened!");
                    }
                    @Override
                    public void onMessage(String message) {
                        Window.alert("Received: " + message);
                    }

                    @Override
                    public void onError(SocketError error) {
                        Window.alert("Error: " + error.getDescription());
                    }

                    @Override
                    public void onClose() {
                        Window.alert("Channel closed!");
                    }
                });
            }
        });
この記述は、Tokenを入手した直後にするのが無難でしょう。接続が確立すると、onOpenメソッドが反応します。この処理を終えることで、サーバとのcomet接続が維持されます。

Pushの呼び出し
上記の処理が終えた後、サーバー側でpushをする処理(前日の記事を参照)を実行させれば、上記のonMessageが反応します。push処理の呼び出し方は、サーブレットでもいいし、GWT-RPCでもいいです。

正直、なんでこれでpushされてくるのかイマイチがところはあります(笑)。サンプルとか殆どないのでわかりにくいですが、cometのことがわかっていれば理解可能だと思います。

2011-04-20

GAEのChannelAPIを理解する ~サーバ編~

GAEで、1.4から採用されたChannel APIについてちょっとわかってきたので簡単に報告します。

ChannelAPIとは
これは俗にいうCometの処理に相当します。チャットのようなPushするプログラミングを作成する際に、GAEのリソースを利用して実装できるというのは大きな魅力でしょう。

ChannelAPIにおいて理解しておくべき最低限の用語2つ
  • Token ・・・ ユーザとコネクションを貼るためのトークン。サーバーは最初の接続要求の時に、このTokenの値をクライアントに渡す必要があります。
  • channelKey ・・・接続チャンネル。ユーザごとに区別するような方法が一般的らしい。
最初の接続処理Tokenの生成部分
ChannelService channelService = ChannelServiceFactory.getChannelService();
String token = channelService.createChannel(channelKey);

//ここで生成されたtokenをクライアントに渡すこと


プッシュ処理(ユーザへの送信)部分
String message="なにか来ました"
ChannelService channelService = ChannelServiceFactory.getChannelService();
channelService.sendMessage(new ChannelMessage(channelKey, message));

とまあ、驚くほど簡単にできたりします。

ちょっとchannelKeyの設定の仕方はいろいろあるようですが、例えば1つに固定にしておくとそのchannelKeyで接続したユーザ全てに同じメッセージを送ることができました。単純にブロードキャストするだけでしたら、そういった方法もいいかもしれません。個別にプッシュ対応する場合は、該当するchannelKeyに対してのみ、sendMessageメソッドを呼び出せば良いのでしょう。

なお、GAE上で本格的に稼働させたわけではないので、どれぐらいの負荷がかかるのかは不明です。

クライアント編については、また後日。。。

2010-12-10

[GWT] Cometでプッシュプログラミング ~クライアントプログラミング編~

GWTでCometサーバーにアクセスするクライアントプログラムの実装方法についてです。

基本的には、通常のサーバアクセスと同様にRequestBuilderを利用してCometサーバに非同期にアクセスします。Cometからデータが送られてくると、onResponseReceivedメソッドが呼ばれるのでそこで内容を抽出し処理を行います。処理が終わったら、再帰的に接続処理を呼び出すことで、Cometサーバとの通信を継続して処理することができます。

private void connectComet() {
        try {
            Window.alert("CometConnect()");
            RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, cometURL);
            
            requestBuilder.sendRequest(null, new RequestCallback() {
                @Override
                public void onResponseReceived(Request request, Response response) {
                  String tmp= response.getText();
                  connectComet();
                }
                @Override
                public void onError(Request request, Throwable exception) {
                                  }
            });
        } catch (RequestException ex) {
            //エラー処理をここで書く
        }
    }


2010-12-06

[Java]Cometプログラミング ~Glassfishの設定~

ここでは、Glassfishをサーバにした際の設定について取り上げます。また、開発環境としてNetbeansを利用する場合についても取り上げます。

[Glassfishでの設定]
Cometを利用する際、古い記事を見るといろいろ設定が必要なような記述がみられますが、Glassfish v3では標準で Cometをサポートしていますので設定は簡単です。手順としては

  1. 管理コンソールを立ち上げる(4848が標準ポートです)
  2. ネットワーク設定→プロトコル→http-listerner-1を開く
  3. Cometサポートを有効にする

これだけでOKです。

[Netbeansで利用する場合]
Netbeansには、標準でGlassfishがついてきます(これがNetbeansをオススメする理由の一つでもあるんですが)。同様にすればいい、、、と思ってるとドツボにハマります。
実は、NetbeansでGlassfishの管理コンソールで設定した内容は一時的なもので、サーバを再起動すると設定が標準に戻ってしまいます。どうすればいいのかというと、

  1. Netbeansでサービスペインをクリック
  2. サーバ→Glassfishを右クリックし、プロパティを選択
  3. Cometサポートを有効にする

という手順をふみます。これがわからず、設定ファイルをいじったりして悩んでました。(^^ゞ

2010-12-03

[Java] Cometでプッシュプログラミング ~サーバプログラミング編~

サーバーサイドからのプッシュ配信を実現するフレームワークとしてCometというのがあります。これは昔からありまして、うちの研究室でも数年前の卒論で利用してました。で、今年も利用することになったんですが、ノウハウを整理しきれてなくて卒論だけ見てもわかりにくい状況になってましたので、ここであらためて整理しておきます。

12/6 プログラムに一部追記しました。

Cometの原理
httpで接続したコネクションを接続しっぱなしにして、レスポンスのストリームにデータを流し込むことでプッシュを実現します。

クラス構成
サーバー側では少なくとも3つのクラスが必要です
  • Cometサーバ実装クラス ・・・ プッシュするためのコネクションを確保するクラス。サーブレットです
  • Cometハンドルクラス ・・・ CometHandlerを実装したクラス。ここにプッシュで送信する処理を記述します。
  • ユーザプログラム ・・・ Cometを利用するプログラムです。

関連ライブラリ
Glassfishには
  • grizzly-comet.jar
というライブラリが同梱されています。このファイル名で探せば出てくるはずですから、見つけたらクラスパスに設定しましょう。

 Cometサーバプログラム
 クライアントとの接続を確保します。まず、init内では
  • Cometエンジンの登録
  • Cometエンジンの設定
を行います。そして、ユーザからコネクション要求があれば、processRequest(サーブレットのdoGet、doPost相当)内で、以下のように書かれている処理を行います。
  • Cometエンジンの呼び出し
  • Cometハンドラーへのコネクションストリームの受け渡し
  • Cometハンドラーの登録
//初期設定
    @Override
    public void init(ServletConfig config) throws ServletException {
        cometContextPath = config.getServletContext().getContextPath() + "/comet";
        System.out.println("cometContextPath:"+cometContextPath);
        CometContext context = CometEngine.getEngine().register(cometContextPath);
        context.setExpirationDelay(10 * 60 * 60 * 1000);
    }
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        //CometHandlerクラスの登録
        CometHandler handler = new MyHandler();
        handler.attach(out);
        CometContext context = CometEngine.getEngine().getCometContext(cometContextPath);
        context.addCometHandler(handler);
    }
Cometハンドラー Cometハンドラーとは何か?それは、Cometでの配信時の処理を記述するクラスです。ここで大切なのは、onEventメソッドです。これは、Pushする際に呼ばれるメソッドです。ここでwriterに対して書き込みを送ることで、クライアントにその内容が配信されます。なぜでしょう?それは、ここのwriterというのは、上記のサーバプログラムでハンドラーを登録する際にattachメソッドにて受渡したHttpServletResponseのWriterの事なのです。
public class MyHandler implements CometHandler<PrintWriter> {

    private PrintWriter writer = null;

    public void onEvent(CometEvent event) throws IOException {
        if (CometEvent.NOTIFY == event.getType()) {

           String id = (String) event.attachment();
            writer = response.getWriter();
            writer.write(id);
            writer.flush();
            event.getCometContext().resumeCometHandler(this);
        }
    public void onInitialize(CometEvent event) throws IOException {
        System.out.println("Init");
    }

    public void onTerminate(CometEvent event) throws IOException {
        onInterrupt(event);
    }

    public void onInterrupt(CometEvent event) throws IOException {
        writer.close();
        event.getCometContext().removeCometHandler(this);
    }
 //クライアントとのストリームを受け取る
    public void attach(PrintWriter writer) {
        this.writer = writer;
    }
   private void removeThisFromContext() throws IOException {
        response.getWriter().close();
        CometContext context =
                CometEngine.getEngine().getCometContext(cometContextPath);
        context.removeCometHandler(this);
    }



ユーザプログラム ユーザプログラムでの記述は下記の通りです。以下はサーブレットの例ですが、ポイントは最後の行です。notifyメソッドを呼ぶことで、CometハンドラークラスのonEventが呼ばれることになります。つまり、プッシュしたい時にnotifyを呼び出せば良いわけです。引数は、ハンドラーのonEventメソッドでeventのアタッチメントとして取り出すことができます。
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        ServletConfig config=this.getServletConfig();
        String id = request.getParameter("id");
        CometContext context = CometEngine.getEngine().getCometContext(cometContextPath);
        context.notify(id);
 }
以上の3つを見比べることで、Cometが何をやっているのかわかるでしょう。コメットのサーバの設定や、クライアントプログラムの記述については、後日書こうかと思ってます。