以下、Jetty 8.1.4.v20120524の話。
JettyでWebSocketサーバを実装する場合、WebSocketServletはWebSocketインターフェースを具象化したクラスを返す必要がある。
また、JettyをWebSocketクライアントとして使った場合もWebSocketインターフェースを使う。
さらに、WebSocketインターフェースは、OnFrame・OnControl・OnTextMessage・OnBinaryMessageの4つのインターフェースに派生する。
WebSocketインターフェースは以下の2つの抽象メソッドを持つ。
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);
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);
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の世界に入っていないので、他とは異質な流れとなっている。
これら全て用途が違うため、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
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に設定し実行。
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();
}
}
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
);
}
}
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>
<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>