悪くないモンスターの太一です。
最近はjsばっかり書いてますけども一番得意な言語はJavaです。
- ryushi@twitter
- taichi@GitHub
- taichi#1881 @ Diablo3
- 今週のオススメはXCOM Enemy UnknownとFaster Than Lightです。
- Jettyとは何か
- SPDY
- 主要なコンポーネントの概要説明
- GroovyでSPDYサーバを実行する
- WebSocket
- 主要なコンポーネントの概要説明
- GroovyでWebSocketサーバを実行する
- WebSocketサーバをSPDY上で実行する
- まとめ
Jettyとは何か?
- Javaで実装されたHTTPサーバ。
- デフォルト非同期I/O。
- JEE6 WebProfile実装なのでServletをデプロイ出来る。
- ニッチで先進的な機能が満載。
- 比較的コードがクリーンでライセンスが緩いのでハックし易い。
- Stableリリースは7系、8系、9系があるので最新の9系ベースで話をする。
- Eclipse Public License - Version 1.0 / Apache License - Version 2.0
- 主にintalioの人がメンテナンスしている。
- npn-boot
- npn-api
- spdy-core
- spdy-client
- spdy-server
- spdy-http-server
- Java用のNext Protocol Negotiation Extension実装。
- OpenJDKの名前空間である sun.security.ssl をダーティハックしている為、GPL。
- eclipse foundationでは無く、mortbay.org名義でリリースしているが、作業している人は同じなので単に政治的なアレだと思う。
- Javaがセキュリティアップデートする度に修正が入ったものがリリースされる。
final public class SSLEngineImpl extends SSLEngine
_人人 人人人_
> 突然のGPL <
 ̄Y^Y^Y^Y^Y ̄
- NPNをJettyから使う為のラッパーレイヤー
- クラスは1つしかないので特に見るべきものは無い
- SPDYプロトコルを実装しているモジュール
- 対応しているバージョンはV2とV3
- org.eclipse.jetty.spdy
- SPDY実装の中心
- org.eclipse.jetty.spdy.api
- SPDYの基礎的な仕様及びデータ構造定義
- org.eclipse.jetty.spdy.frames
- フレーム構造の定義
- org.eclipse.jetty.spdy.generator
- 出力仕様に対する実装
- org.eclipse.jetty.spdy.parser
- 入力仕様に対する実装
- 酷いコードの様に見えるかもしれないけど、Javaでプロトコルパーザを普通に書いたらこんなもん。 SynReplyBodyParser.javaだけ抜粋しておいたので見て下さい。
- 非同期I/OベースのSPDYクライアントライブラリ
- SPDYに対応しているサーバをクローリングするなら速いかも
- 自前SPDYサーバを自動テストするのに使うと良いかも?
- Jettyのサーバフレームワーク上に実装されているSPDYのサーバ実装
- 主にSPDY用TCPコネクションの管理コード
- HTTP上で動作する為のサーバ処理
- 文字列に関する処理は全部ここ
- SPDY-http-proxyの実装
- JettyをSPDYサーバとして使う場合このモジュールを使う
new org.eclipse.jetty.server.Server().with {
def connector = new org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnector(it,
new org.eclipse.jetty.util.ssl.SslContextFactory(
keyStorePath: 'src/main/resources/spdy.jks',
keyStorePassword: 'password',
protocol: 'TLSv1'))
connector.port = 8443
addConnector connector
handler = new org.eclipse.jetty.server.handler.ResourceHandler(
resourceBase: 'src/main/resources/webcontent')
start()
join()
// https://localhost:8443/spdy.html
// chrome://net-internals/#spdy
}
運用系のコード無しにSPDYサーバ起動するだけなら20行程度のコードで動く。
このコードは起動する時にnpn-bootをJVMの起動オプションで渡す。
eclipseの場合は Run Configurations ... > Arguments > VM arguments に以下の様な設定を行う。
-Xbootclasspath/p:${project_loc}/lib/npn-boot-1.1.5.v20130313.jar
これを忘れると、以下の様にエラーメッセージが出力されサーバが起動しない。
2013-03-27 20:33:21.240:WARN:oejss.NPNServerConnectionFactory:main: NextProtoNego not from bootloader classloader: sun.misc.Launcher$AppClassLoader@59727745
2013-03-27 20:33:21.240:WARN:oejss.NPNServerConnectionFactory:main: NextProtoNego not available: java.lang.IllegalStateException: NextProtoNego not on bootloader
Exception in thread "main" java.lang.IllegalStateException: NextProtoNego not available
at org.eclipse.jetty.spdy.server.NPNServerConnectionFactory.<init>(NPNServerConnectionFactory.java:64)
尚、Jetty8 系でこの設定を忘れるとHTTPリクエストを送信した際にCPU使用率が100%に張り付く等、愉快な事が起こる。
- websocket-api
- websocket-common
- websocket-client
- websocket-servlet
- websocket-server
- アプリケーションでは直接使うべきではないものである。
- 例えば、CometD の様な抽象度が高いフレームワークを使うべき。
- CometDなら、long pollingとWebSocketをjsのランタイムから使い易い様に使える。
- Jetty/Feature/WebSockets
- WebSocketAPIなので実装はほぼ無くinterfaceの定義が中心。
- Futureパターンによる非同期I/O
- JettyでWebSocketするなら理解する必要がある。
- JavaEE7ではWebSocketが使える様になる。
- WebSocketプロトコルを実装しているモジュール
- RFC6455実装
- 以前は様々なバージョンのWebSocketに対応していたがJetty9で大胆に削除
- org.eclipse.jetty.websocket.common
- Parser見とけばJavaでのWebSocket実装は大体分かる。
- org.eclipse.jetty.websocket.common.events
- WebSocketにおけるサーバとアプリケーションのGlueコードが記述されている。
- org.eclipse.jetty.websocket.common.extensions.compress
- org.eclipse.jetty.websocket.common.extensions.fragment
- org.eclipse.jetty.websocket.common.extensions.identity
- fragmentとidentityは、よく分からない。
- org.eclipse.jetty.websocket.common.extensions.mux
- 非同期I/OベースのWebSocketクライアントライブラリ。
- multiplexing対応のコードもある。
- ServletとしてWebSocketアプリケーションをデプロイする為のライブラリ。
- JettyでWebSocketするなら、このモジュールを使う。
- Jettyのサーバフレームワーク上に実装されているWebSocketのサーバ実装。
- multiplexing対応を含むWebSocket用TCPコネクションの管理コード。
- ExampleEchoServer.javaを見れば使い方は大体分かる。
@org.eclipse.jetty.websocket.api.annotations.WebSocket
class Echo {
@org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage
void onText(org.eclipse.jetty.websocket.api.Session session, String msg) {
session.getRemote().sendStringByFuture(msg)
}
}
new org.eclipse.jetty.server.Server(8080).with {
handler = new org.eclipse.jetty.websocket.server.WebSocketHandler.Simple(Echo)
handler.handler = new org.eclipse.jetty.server.handler.ResourceHandler(
resourceBase: 'src/main/resources/webcontent')
start()
join()
// http://localhost:8080/
}
@org.eclipse.jetty.websocket.api.annotations.WebSocket
class DoubleEcho {
@org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage
void onText(org.eclipse.jetty.websocket.api.Session session, String msg) {
session.getRemote().sendStringByFuture("$msg $msg")
}
}
new org.eclipse.jetty.server.Server().with {
def connector = new org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnector(it,
new org.eclipse.jetty.util.ssl.SslContextFactory(
keyStorePath: 'src/main/resources/spdy.jks',
keyStorePassword: 'password',
protocol: 'TLSv1'))
connector.port = 8443
addConnector connector
handler = new org.eclipse.jetty.websocket.server.WebSocketHandler.Simple(DoubleEcho)
handler.handler = new org.eclipse.jetty.server.handler.ResourceHandler(
resourceBase: 'src/main/resources/webcontent')
start()
join()
// https://localhost:8443/
// chrome://net-internals/#spdy
}
JettyではSPDYはコネクタ系のモジュールでWebSocketはハンドラ系のモジュールなので特に難しい事を考えずとも同時に実行可能です。
- Javaでプロトコルパーザを書くと酷い
- Jettyは全体的に非同期I/O
- JettyのWebSocketはCometD越しに使うのがオススメ
- SPDYの上にWebSocket乗せるのは楽勝