Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Socket.IO 1.0の変更点・内部的な話
Search
Naoyuki Kanezawa
June 23, 2014
Programming
20
9.3k
Socket.IO 1.0の変更点・内部的な話
socket.io 1.0と0.9の比較や内部実装について。 node学園#13
Naoyuki Kanezawa
June 23, 2014
Tweet
Share
More Decks by Naoyuki Kanezawa
See All by Naoyuki Kanezawa
Introducing Now and Next.js
nkzawa
12
5.5k
WebSocketの圧縮機能とSocket.IO
nkzawa
5
9.1k
Socket.IO 1.0 Client for Javaの紹介
nkzawa
5
1.8k
Other Decks in Programming
See All in Programming
堅牢なフロントエンドテスト基盤を構築するために行った取り組み
shogo4131
8
2.5k
Developing static sites with Ruby
okuramasafumi
0
320
宅宅自以為的浪漫:跟 AI 一起為自己辦的研討會寫一個售票系統
eddie
0
520
ELYZA_Findy AI Engineering Summit登壇資料_AIコーディング時代に「ちゃんと」やること_toB LLMプロダクト開発舞台裏_20251216
elyza
2
470
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
230
リリース時」テストから「デイリー実行」へ!開発マネージャが取り組んだ、レガシー自動テストのモダン化戦略
goataka
0
130
dotfiles 式年遷宮 令和最新版
masawada
1
800
公共交通オープンデータ × モバイルUX 複雑な運行情報を 『直感』に変換する技術
tinykitten
PRO
0
160
perlをWebAssembly上で動かすと何が嬉しいの??? / Where does Perl-on-Wasm actually make sense?
mackee
0
110
SwiftUIで本格音ゲー実装してみた
hypebeans
0
460
JETLS.jl ─ A New Language Server for Julia
abap34
2
430
LLMで複雑な検索条件アセットから脱却する!! 生成的検索インタフェースの設計論
po3rin
4
910
Featured
See All Featured
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
359
30k
Claude Code のすすめ
schroneko
65
200k
Ten Tips & Tricks for a 🌱 transition
stuffmc
0
30
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
1.8k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
710
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
26
3.3k
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
40
The Mindset for Success: Future Career Progression
greggifford
PRO
0
180
Are puppies a ranking factor?
jonoalderson
0
2.3k
YesSQL, Process and Tooling at Scale
rocio
174
15k
Rails Girls Zürich Keynote
gr2m
95
14k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
0
390
Transcript
Socket.IO 1.0の変更点、内 部的な話 Node学園#13
自己紹介 github: nkzawa twitter: nkzawa socket.io, engine.ioなどにコントリビュートしたり、 socket.io関連モジュールをつくったり。
アジェンダ 1. Engine.IOとUpgrade 2. Middleware 3. バイナリサポート 4. Adapter 5.
プロトコル
Engine.IO と Upgrade
engine.io • トランスポートの違いを吸収して、websocketと同等の機能 を提供するライブラリ。 • socket.io 1.0には名前空間やルーム、自動再接続などの 高レベルな機能のみ実装され、メッセージの送受信は engine.ioを通して行われる。 •
socket.io 0.9で採用されていたfallback方式ではなく upgrade方式でトランスポートを切り替える。
fallback 1. 最初にwebsocketで接続を試みる。 2. 接続できたら終了。 3. 接続できなかった場合、初期設定で最低10秒間タイムアウ トを待つ。 4. タイムアウトしたら、改めてpollingで接続を行う。
=> websocketが使えない場合の初回接続速度に問題があっ た。
upgrade 1. httpのgetリクエストを行い、pollingの接続を確立させる。 2. upgradeできるか判定。設定次第でupgradeは行われず終 了。 3. pollingを維持したまま、並列にwebsocketで通信しパケット の交換ができるかどうかまで試す(probe)。 4.
websocketがつながったらpollingが止まるのを待ち(メッ セージのロスを防ぐため)、メインのトランスポートを切り替 える。
サポートされるトランスポート • websocket • polling ◦ xhr ◦ jsonp ※polling時はxhrが優先的に使用される。
flashsocket ? 公式にはサポートされなくなった。flashsocketに限らず、別のト ランスポートが必要な場合は自作して追加する。 “removed flashsocket, moving to userland” https://github.com/Automattic/engine.
io/commit/10261c52119f2912b72b55bec4df87d91b180525
upgrade関連オプション(client側) transports: [‘polling’, ‘websocket’] 使用するトランスポートを順番に設定する。[‘websocket’] と すると最初からwebsocketで接続することもできる。 rememberUpgrade: false 一度upgradeに成功した後に再接続すると、upgradeプロセ
スを飛ばしてwebsocketで接続する。SSLの時などに有効 にするとよいらしい。
Middleware
middleware ハンドシェイクから接続までの間に、処理を挿入する仕組み。 expressのmiddlewareと似たようなもの。 io.use(function(socket, next) {});
0.9では 0.9ではauthorizationで同様のことができたが、あくまで認証用 の機能で拡張性は低かった。 io.set(‘authorization’, function(handshakeData, fn) { // 認証失敗 fn(null,
false); });
1.0の認証 setメソッドとauthorizationは廃止(後方互換のため残されては いる)。代わりにmiddlewareを使って認証する。 io.use(function(socket, next) { // 接続を閉じる next(new Error(‘not
authorized’);); });
ハンドシェイクデータ ハンドシェイク時のrequestオブジェクトにアクセスでき、そこか らcookieのパースやセッションの復元などが可能。 io.use(function(socket, next) { console.log(socket.request); next(); });
// expressのmiddlewareを使ってcookieをパースする var cookieParser = require(‘cookie-parser’)(‘my secret’); io.use(function(socket, next) {
var req = socket.request; var res = {}; // ダミーのレスポンス cookieParser(req, res, next); }); io.on(‘connection’, function(socket) { console.log(socket.request.cookies); });
ネームスペース middlewareはネームスペース単位。 // デフォルトネームスペース。次の二つは同じ意味。 io.use(function(socket, next) {}); io.of(‘/’).use(function(socket, next) {});
// foo ネームスペース io.of(‘/foo’).use(function(socket, next) {});
実行順序 全てのクライアントは、デフォルトネームスペース(’/’)へ必 ず最初に接続され、’/’ のmiddlewareが実行される。 cookieパーサのように、常に先に実行したいmiddlewareは ‘/’ へ登録する。
// クライアント var socket = io(‘http://localhost:3000/foo’); // サーバ io.use(function(socket, next)
{ console.log(‘first’); // 先に実行される next(); }); io.of(‘/foo’).use(function(socket, next) { console.log(‘second’); // 後で実行される next(); });
バイナリサポート
バイナリサポート 1.0からバイナリデータを送受信できるようになった。オブジェク トや配列に埋め込むんだり、複数バイナリを同時送受信も可 能。 socket.emit(‘event’, new Buffer([0, 1, 2]));
examples // オブジェクトに埋め込み socket.emit(‘event’, {data: new ArrayBuffer(10)}); // 複数バイナリ socket.emit(‘event’,
[binary1, binary2]); // acknowledge socket.on(‘event’, function(callback) { callback(new Buffer([1, 2, 3])); });
0.9でバイナリを扱う 0.9でもバイナリをbase64エンコードした文字列として送受信す ることはできた。ただし、エンコード/デコード処理が入り、データ サイズも増加するため効率はよくない。 socket.emit(‘event’, buffer.toString(‘base64’));
サポートされるデータ形式 • Buffer (node) • ArrayBuffer (node, browser) • Blob,
File (browser)
バイナリ送信できるトランスポート • ◯ websocket • ◯ XMLHttpRequest Level 2 •
☓ 古い仕様のwebsocket • ☓ XMLHttpRequest • ☓ JSONP ※バイナリ送信をサポートしないトランスポートでも、base64エンコードされた文字列 として透過的にデータを送受信できる。
バイナリの扱いに注意 データサイズに制限はないが、メモリへ読み込むので、大きな ファイルの配信などには向かない。 この問題を解決するために、別モジュールによるstream送信の サポートが計画されている。
Adapter
Adapter 複数のサーバ間でメッセージをbroadcastする時に 使用される。0.9にあったStoreの代替。 io.adapter(Adapter);
socket.io-redis 0.9にあったRedisStore相当のadapter。socket.io本体には同 梱されていないので、別途インストールが必要。 var redis = require(‘socket.io-redis’); io.adapter(redis({host: ’localhost’, port:
6379}));
Storeとの違い • Storeのget/set 相当のデータ共有機能がなくな りシンプルに。Adapterが扱うのはbroadcastの み。 • 内部的に使っていたpublish/subscribeがなく なってスケールしやすい設計に。
socket.io 0.9のサーバ間共有設計 クライアントの接続データ(handshakeデータ, 所属ルーム等) は、Storeを通して他のサーバへ通知され保存される。 それぞれのサーバが、他サーバに接続しているものを含む全て のクライアントデータ(の一部)を処理し、保持するためスケール しにくい。
例: socket.io 0.9サーバ10台に、それぞれ1万クライアントが 同時接続する場合。 各サーバそれぞれで10万クライアントのデータが処理・保持さ れる。サーバを増やしても、一つのサーバが処理するデータ数 は変わらず、同時接続数に比例して増える。 サーバA: 10万 サーバB:
10万 … ※あくまでデータの一部なので全くスケールしないわけではないと思われる。
socket.io 1.0のサーバ間共有設計 各サーバは一切データ共有を行わない。 1.0のAdapterでは、broadcastしたパケットとそのオプション データだけが通知され、サーバには何も保存されないためス ケールしやすい。
例: socket.io 1.0サーバ10台に、それぞれ1万クライアントが 同時接続する場合。 各サーバは自身に接続している1万クライアントのデータのみを 処理・保持する。サーバを増やすことで、一つのサーバが処理 するデータ数を減らすことができる。 サーバA: 1万 サーバB:
1万 ...
プロトコル
プロトコルの変化 socket.ioの構成変更や機能追加に伴い、プロトコ ルの大幅な更新が行われた。 • トランスポート層(engine.io)の分離 • バイナリサポート
0.9のパケット コロン区切りのメッセージ [type] : [id] : [namespace] : [data] 例:
5::/nsp:{"name":"foo","args":["hi"]}
0.9のペイロード pollingで一度に複数のパケットを一括送信するの に使用される。\ufffd 区切りでデータ長 +パケットを 連結して繰り返す。 \ufffd [length] \ufffd [packet]
... 例: \ufffd32\ufffd5:::{"name":"foo","args":["hi"]}\ufffd ...
1.0のパケット 区切り文字とJSONのキー名がなくなり効率的に。 データはutf8エンコードされる。 [engine.io type] [type] [namespace] , [data] 例:
42/nsp,["foo","hi"]
1.0のバイナリを含むパケット バイナリ数が追加。バイナリデータはプレースホル ダで置き換えられ、別のパケットとして送られる。 [engine.io type] [type] [binary数] - [namespace] ,
[data] 例: 451-/nsp,["foo",{"_placeholder":true,"num":0}]
1.0のペイロード バイナリ送信をサポートするtransportでは、文字列も全てバイ ナリに変換される。パケットがutf8エンコードされるのはこのた め。 [0(string), 1(binary)] [length(一桁づつ)] 255 [packet] ...
例: [00 02 05 ff 34 32 2f 6e 73 70 2c 5b 22 65 63 68 6f 20 62 61 63 6b 22 2c 22 68 69 22 5d]
1.0のペイロード(文字列) バイナリ送信をサポートしないtransportでは、文字 列のまま送信。バイナリはbase64エンコードされ る。 [length] : [packet] ... 例: 19:42/nsp,["foo","hi"]
プロトコルの変更による影響 socket.io 0.9のプロトコルを実装していた別言語 のsocket.ioサーバ・クライアントは一切使用できな い。 => ユーザが0.9から1.0にアップデートする際の最 も大きな障害になると思われる。
まとめ • engine.ioでより安定したsocket通信ができます。 • middleware便利。モジュールを作って公開しよう。 • バイナリも送受信できるようになった。 • adapterでスケールしやすいアーキテクチャに。 •
0.9から1.0への移行は難しくない。プロトコルの違いには注 意。
thanks!