Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
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
9.3k
20
Share
Socket.IO 1.0の変更点・内部的な話
socket.io 1.0と0.9の比較や内部実装について。 node学園#13
Naoyuki Kanezawa
June 23, 2014
More Decks by Naoyuki Kanezawa
See All by Naoyuki Kanezawa
Introducing Now and Next.js
nkzawa
12
5.6k
WebSocketの圧縮機能とSocket.IO
nkzawa
5
9.3k
Socket.IO 1.0 Client for Javaの紹介
nkzawa
5
1.8k
Other Decks in Programming
See All in Programming
それはエンジニアリングの糧である:AI開発のためにAIのOSSを開発する現場より / It serves as fuel for engineering: insights from the field of developing open-source AI for AI development.
nrslib
1
830
VueエンジニアがReactを触って感じた_設計の違い
koukimiura
0
160
Java 21/25 Virtual Threads 소개
debop
0
330
Codex CLIのSubagentsによる並列API実装 / Parallel API Implementation with Codex CLI Subagents
takatty
2
860
ドメインイベントでビジネスロジックを解きほぐす #phpcon_odawara
kajitack
2
110
年間50登壇、単著出版、雑誌寄稿、Podcast出演、YouTube、CM、カンファレンス主催……全部やってみたので面白さ等を比較してみよう / I’ve tried them all, so let’s compare how interesting they are.
nrslib
4
720
Coding as Prompting Since 2025
ragingwind
0
760
Swift Concurrency Type System
inamiy
0
290
RSAが破られる前に知っておきたい 耐量子計算機暗号(PQC)入門 / Intro to PQC: Preparing for the Post-RSA Era
mackey0225
3
120
Smarter Angular mit Transformers.js & Prompt API
christianliebel
PRO
1
120
20260320登壇資料
pharct
0
160
Going Multiplatform with Your Android App (Android Makers 2026)
zsmb
2
350
Featured
See All Featured
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
140
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.4k
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
760
Typedesign – Prime Four
hannesfritz
42
3k
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
1
510
Into the Great Unknown - MozCon
thekraken
40
2.3k
Code Reviewing Like a Champion
maltzj
528
40k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
38
2.8k
The Curious Case for Waylosing
cassininazir
0
290
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
180
Mobile First: as difficult as doing things right
swwweet
225
10k
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.4k
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!