« おとうさんはプログラマ その5 〜アイちゃん、『命令(めいれい)のかたまり』に名前をつける〜 | メイン | JettyのWebSocketでPing/Pongフレームを送る »

JettyでWebSocketを使うときのコールバックイベントの実行順

以下、Jetty 8.1.4.v20120524の話。

JettyでWebSocketサーバを実装する場合、WebSocketServletはWebSocketインターフェースを具象化したクラスを返す必要がある。
また、JettyをWebSocketクライアントとして使った場合もWebSocketインターフェースを使う。

さらに、WebSocketインターフェースは、OnFrame・OnControl・OnTextMessage・OnBinaryMessageの4つのインターフェースに派生する。

WebSocketインターフェースは以下の2つの抽象メソッドを持つ。
// WebSocket
void onOpen(Connection connection);
void onClose(int closeCode, String message);
OnFrame・OnControl・OnTextMessage・OnBinaryMessageaの4つのインターフェースに定義されている抽象メソッドは以下。
// OnFrame
boolean onFrame(byte flags,byte opcode,byte[] data, int offset, int length);
void onHandshake(FrameConnection connection);

// OnControl
boolean onControl(byte controlCode,byte[] data, int offset, int length);

// OnTextMessage
void onMessage(String data);

// OnBinaryMessage
void onMessage(byte[] data, int offset, int length);
OnTextMessageインターフェースやOnBinaryMessageインターフェースはメッセージの受信に使用でき、OnControlインターフェースは切断処理やPing/Pong処理に、OnFrameインターフェースは低レイヤーの処理に使える。
これら全て用途が違うため、4つ全部を具象化することもあり得る。

では、どういう順番で各メソッドは呼ばれるのか。
WebSocketサーバ上で、メソッドが呼ばれたタイミングで引数と共にprintlnして処理順を調べた。
処理の流れは、OnFrameインターフェースの抽象メソッドを具象化したメソッドが呼ばれた後に、受け取ったopcodeにあった別のインターフェースの具象メソッドが呼ばれるような具合。
ハンドシェイクの処理はまだWebSocketの世界に入っていないので、他とは異質な流れとなっている。
// 接続
doWebSocketConnect / request : (GET /)@1508249638 org.eclipse.jetty.server.Request@59e61026 / protocol : null
onHandshake / connection : WSFrameConnection@672ae2bc l(0:0:0:0:0:0:0:1%0:8080)<->r(0:0:0:0:0:0:0:1%0:50671)
onOpen / connection : WSFrameConnection@672ae2bc l(0:0:0:0:0:0:0:1%0:8080)<->r(0:0:0:0:0:0:0:1%0:50671)

// テキストメッセージ受信
onFrame / flags : 8 / opecode : 0x1 / data length : 8192 / offset : 6 / length : 6
onMessage / data : foobar

// 切断
onFrame / flags : 8 / opecode : 0x8 / data length : 8192 / offset : 6 / length : 0
onControl / controlCode : 0x8 / data length : 8192 / offset : 6 / length : 0
onClose / closeCode : 1005 / message : null
以下、検証コード。
mavenでjetty:runをgoalに設定し実行。
CheckWebSocketServlet.java
package com.kanasansoft.JettyWebSocketEventCheck;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;

import org.eclipse.jetty.websocket.WebSocket;
import org.eclipse.jetty.websocket.WebSocketServlet;

@WebServlet("/*")
public class CheckWebSocketServlet extends WebSocketServlet {

    private static final long serialVersionUID = 1L;

    public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {
        System.out.println(
            "doWebSocketConnect"
                + " / request : "     + request
                + " / protocol : "    + protocol
        );
        return new CheckWebSocket();
    }

}
CheckWebSocket.java
package com.kanasansoft.JettyWebSocketEventCheck;

import org.eclipse.jetty.websocket.WebSocket;

public class CheckWebSocket implements WebSocket, WebSocket.OnFrame, WebSocket.OnControl, WebSocket.OnTextMessage, WebSocket.OnBinaryMessage {

    public void onHandshake(FrameConnection connection) {
        System.out.println(
            "onHandshake"
                + " / connection : "  + connection
        );
    }

    public boolean onFrame(byte flags, byte opcode, byte[] data, int offset, int length) {
        System.out.println(
            "onFrame"
                + " / flags : "       + flags
                + " / opecode : "     + "0x" + Integer.toString(opcode, 16)
                + " / data length : " + data.length
                + " / offset : "      + offset
                + " / length : "      + length
        );
        return false;
    }

    public boolean onControl(byte controlCode, byte[] data, int offset, int length) {
        System.out.println(
            "onControl"
                + " / controlCode : " + "0x" + Integer.toString(controlCode, 16)
                + " / data length : " + data.length
                + " / offset : "      + offset
                + " / length : "      + length
        );
        return false;
    }

    public void onOpen(Connection connection) {
        System.out.println(
            "onOpen"
                + " / connection : "  + connection
        );
    }

    public void onClose(int closeCode, String message) {
        System.out.println(
            "onClose"
                + " / closeCode : "   + closeCode
                + " / message : "     + message
        );
    }

    public void onMessage(String data) {
        System.out.println(
            "onMessage"
                + " / data : "        + data
        );
    }

    public void onMessage(byte[] data, int offset, int length) {
        System.out.println(
            "onMessage"
                + " / data length : " + data.length
                + " / offset : "      + offset
                + " / length : "      + length
        );
    }

}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.kanasansoft.JettyWebSocketEventCheck</groupId>
  <artifactId>JettyWebSocketEventCheck</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>JettyWebSocketEventCheck</name>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.1.1</version>
        <configuration>
          <failOnMissingWebXml>false</failOnMissingWebXml>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
  <dependencies>
    <dependency>
      <groupId>javax</groupId>
      <artifactId>javaee-web-api</artifactId>
      <version>6.0</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-servlets</artifactId>
      <version>8.1.4.v20120524</version>
    </dependency>
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-websocket</artifactId>
      <version>8.1.4.v20120524</version>
    </dependency>
    </dependencies>
</project>

コメントを投稿

(いままで、ここでコメントしたことがないときは、コメントを表示する前にこのブログのオーナーの承認が必要になることがあります。承認されるまではコメントは表示されません。そのときはしばらく待ってください。)

Google

タグ クラウド