websocketについて 会津大学 RFC輪読会

スポンサーリンク
プログラミング

この記事について

この記事はいつしかやった会津大学RFC輪読会にて、僕が読んだものをまとめていて、公開し忘れていたものです。

読んだRFCはWebSocketについての RFC6455
https://tools.ietf.org/html/rfc6455
日本語役があります。
https://triple-underscore.github.io/RFC6455-ja.html

WebSocketは前々から色々と使っていて、ライブラリを使っている際にちょくちょく疑問点あったので、このタイミングで読めてよかったです。


ここから僕のメモ件、まとめたものです。

WebSocketとは

サーバーの更新を伝えるために、めっちゃポーリングされてていてそれはTCP接続が増える、上にリクエスト毎にHTTPヘッダがが含まれるためにオーバーヘッドが大きい
解決策として、クライアント、サーバー両方向用にに単独のTCP接続を利用する。

HTTPをトランスポート層に利用していて、HTTPプロキシやフィルタリングもサポートできるようになっている。

WebSocket通信

WebSocketの通信は、ハンドシェイクとデータ転送からなリマス。

WebSocket通信

WebSocketの通信は、ハンドシェイクとデータ転送からなリマス。

スポンサーリンク

開始ハンドシェイク

Client

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

一行目はWebSocketのエンドポイントを識別する
Sec-WebSocket-Protocol はクライアントが受けられるアプリの指示に使える。一つのHTTP Requestに複数のヘッダがあってもおk
Originはブラウザから送信する際につくもので、オリジンが違う接続を却下できる
Sec-WebSocket-Keyにクライアントが生成したランダムな長さが16バイトの列をbase64エンコードしたもののnonce。

Sec-WebSocket-Versionは13が固定で指定される

サーバー

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat

Sec-WebSocket-AcceptはクライアントがSec-WebSocket-Keyで送ったものをハッシュを構築したものを含めて返す。
これがない場合接続が確立されない。
Sec-WebSocket-ProtocolにはサーバーがクライアントのSec-WebSocket-Protocolから自分が話せるプロトコルを一つ選択しつける。

データの送信

ハンドシェイクが成功したら、サーバー、クライアントが独立してデータを送信できる。
“messages”と呼ばれる概念的な単位で区切られているデータを相互に転送する。
一つのmessageは一つ以上のフレームからできている。

フレーム

データの種類
- テキスト
– バイナリ
– 制御用(closeなど)
– ping, pong
– 追加ように予約されているものがいくつかある。

これは例えばGoのWebSocketライブラリである /gorilla/websocketの場合

if err := conn.WriteMessage(messageType, p); err != nil {
    log.Println(err)
    return
}

messageTypeで指定するものです。
ここで渡しているmessageTypeintなのですが、その値は以下のようになっています。

0x01テキスト
0x02バイナリ
0x03~0x07追加のデータフレームに予約ずみ
0x08close
0x09ping
0xApong
0xB~0xF追加の制御フレームに予約済み

終了ハンドシェイク

双方が終了の制御フレームを遅れるので、最初にCloseを送った方が、相手がCloseを送ったら接続を切る。

URIについて

ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ]
wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]

例: wss://example.com/websocket?query="hogefuga"

セキュリティとか

  • 接続の機密性、安全性はTLS通す必要があるのでwssを使う
  • ブラウザ以外からも通信できるので、予期しない方法でアクセスされている可能性を考慮する必要がある。

以上です。

終わりに

簡単かと思いきや結構量があって難しかったです。まだ全部は読みきれませんでした。
双方向通信は最近だとHTTP2を用いたgRPCなんかが出ていますが、~gRPCはまだstreaming対応していないような~
https://github.com/grpc/grpc-web#3-write-your-js-client
Streaminに対応しているようです。
Webも対応してるみたいなので、WebSocketの代用にgRPC Streamも良さそうですね

コメント

タイトルとURLをコピーしました