WebSocket・HTTP通信まとめ

#はじめに
WebSocket通信について理解を深めるため調査しました。そもそもHTTP通信も理解できているのか怪しい…ということもあったため、その周辺知識もギュッとまとめています。
自分用メモですが、誰かのためになれば嬉しいです。


##WebSocket通信
WebSocketとはネットワークの通信規格の一つ。ウェブアプリケーションにおいて、双方向通信を実現するために生まれた技術。WebSocketは双方向通信を実現する。（対義語は単方向通信）即時性を求めるようなアプリケーションにおいて、WebSocketは有効。

参考：
http://wild-data-chase.com/index.php/2019/03/17/post-630/
https://qiita.com/yuba/items/00fc1892b296fb7b8de9
https://www.keicode.com/script/html5-websocket-1.php

##単方向通信
クライアントからサーバーへ情報をpushするだけで、サーバーからクライアントへ情報をpushできない。
例：ネット掲示板などでは、クライアントがブラウザから掲示板に書き込みを行ったとき、その書き込み情報はサーバーに送られる。書き込みはサーバーに保持されるが、その情報はサーバーが次にサーバーが情報取得のリクエストを受け取って初めてクライアントにサーブされる。つまり、書き込みがリアルタイムで他のクライアントのブラウザに反映されることはない。つまり、サーバー手動で情報をpushできない。

##双方向通信
クライアントからサーバーへ情報をpushするだけでなく、サーバーからクライアントへ情報をpushできる。
例：チャットルームに既に複数人のユーザーがいると仮定する。一人のユーザーが書き込みを行ったとき、その情報はサーバーに送られサーバーで保持される。ここでサーバーは能動的に情報をpushする機能を持ち合わせているため、サーバーに情報が届いた時点で他のクライアントにその情報をサーブすることができる。つまり、書き込みがリアルタイムで他のクライアントのブラウザに反映されることになる。つまり、サーバー手動で情報をpushできる。


##WebSocket成り立ち
通常、WebというとプロトコルにはHTTPが使用される。一般的なホームページを作ってそれを公開すると、ユーザーはそのページにリクエストをサーバーに投げて、サーバーはそれを受けてページ情報をユーザーにレスポンスする。このとき、レスポンスされた時点でユーザーの要求は満たされるため、一旦接続は切断される。
しかし、これだとサーバー側が手動でユーザーに情報を送信することができない。この問題を解決するために生まれたプロトコルがWebSocketである。

##WebSocket利点
WebSocketではクライアントとサーバーの接続を成立させた後、その接続を切断せずに維持し続ける。これにより、クライアント、サーバー相互に情報を相手に送信することができるようになる（双方向通信）。また、リクエスト・レスポンスを毎回行わず、情報の送受信をコネクション上で小さなフレームのやりとりによって行うため、HTTPに比べて送受信にかかるデータの総量が減少する。

##WebSocket コネクションの張り方
コネクションの張り方自体は、HTTPとそれほど変わりはない。HTTPではコネクション形成のためにスリーウェイ・ハンドシェイクという手法でとるが、WebSocketの場合もほど同様で、WebSocket openingハンドシェイクという手法をとる。
なお、コネクションを管理するためWebSocketはTCPの技術。

>スリーウェイ・ハンドシェイクとは：
　データ転送を行う前にコネクションの確立を“3回のやりとり" によって行うこと。
　①「接続を開始していい？」
　②「OK！こちらからも接続を開始してもいい？」
　③「OK！」　→通信の確立

>TCPとは：通信相手の応答があってはじめて通信を開始するコネクション型プロトコル

参考：スリーウェイ・ハンドシェイクとは
・https://www.infraexpert.com/study/tcpip9.html
・https://wa3.i-3-i.info/word15428.html

##HTTPプロトコルじゃダメ？
HTTPではkeep-aliveという機能が追加されており、一度形成したコネクションをタイムアウトなどが起きるまで維持することができる。WebSocketもコネクションを形成した後にそれを維持し、その中で双方向通信を行うため、一見HTTPのkeep-aliveと等価であるように思える。しかし、<font color="red">HTTPのkeep-aliveはコネクションを維持するだけで、サーバーからのpush機能は実現していない。</font>この機能は「通信の度にコネクションを張り直す」というHTTPの負荷デメリットを解消するためのもの。

>keep-alibeとは：
ある2つの機器間の通信接続において、相手が活きているかを確認し、その接続を維持する仕組み

参考：HTTPの歴史
https://www.kagoya.jp/howto/webhomepage/http-2/

参考：keep-alive
https://milestone-of-se.nesuke.com/nw-basic/as-nw-engineer/keepalive-tcp-http/

##WebSocket以外の双方向通信について
HTTP上でも双方向通信を実現することができるが、デメリットを抱えておりWebSocketがベターになっている。

HTTPで双方向通信を実現する方法：
　・Ajaxポーリング
　・Server Sent Events（SSE）
　・Comet（コメット）
など

>ポーリングとは：
主となるシステムが他のシステムに対して一定間隔で順繰りに要求がないか尋ねる方式。
各システムが自らのタイミングで通信を行うと処理や信号が他のシステムと競合して不具合を生じる場合がある。
参考：
https://qiita.com/philip_runner/items/7ffd9347430830270519

参考：
・https://www.kimullaa.com/entry/2016/01/17/231359
・https://future-hearts.com/2019/06/15/realtime-web-app/



##Ajaxポーリング
Webページの一部を動的に更新し続けることができる。これはページ全体ではなく一部に対してサーバーとの通信を命じているからである。<font color="red">定期的にサーバーにリクエストを送り続け、サーバーがそれに対して毎回レスポンスを返す。</font>
これにより擬似的にリアルタイムのようにサーバーの情報をクライアントが取得することができる。しかし、厳密に言えば、クライアントのリクエストに対してサーバーが応答しているだけであり、サーバーが保持する情報に変更があった時に、サーバー主導で情報をpushしているわけではない。つまり、双方向通信ではない。
また、サーバーが保持する情報に変更がなかったとしてもクライアントはリクエストを送り続けなければならないため、その点でも負荷がある。

参考：Ajaxについて
https://qiita.com/tatsuya_1995/items/7191c0d39388b9d13e6e

##Server-sent Events(SSE)
クライアントとサーバーでコネクションを張り、レスポンスを閉じずstreamとしてサーバーからデーターを返す形式。
サーバーからクライアントへの一方向のデータ送信のみ可能。サーバーからpush通信を行うという点ではWebSocketと同様であるが、Cometの発展形という仕様のため、使用範囲が限られる。

>streamとは：
通信ネットワークの分野では、データを送受信する際にデータ全体の受信完了を待たずに受信したデータから順番に処理を行う送受信方式（ストリーミング）や、そのように送受信される連続的なデータの流れをストリームという。

参考：https://labs.gree.jp/blog/2014/08/11070/
私がやってみたいことメモ：https://qiita.com/okumurakengo/items/cbe6b3717b95944083a1

##Comet（コメット）
擬似的にサーバーpushを実現する方法。クライアントがサーバーにリクエストを送った時、通常はサーバーがそれに対するレスポンスをすぐにサーブするが、Cometではサーブしない。Cometはクライアントからリクエストを受け取った時、リクエスト対象の情報に変更があるまでレスポンスを保留し、<font color="red">情報に変更が生じた時に初めてレスポンスをサーブする。</font>
情報の変更がトリガーとなってサーバーがレスポンスをサーブするので、ポーリングよりも高速に情報の返却が可能であり、厳密にはサーバーpushではないもの、ほぼリアルタイムに応答することができる。
ただし、レスポンスがサーブされた後に再度クライアントがリクエストを送るが、この間にサーバーが保持する情報に変更があった場合、うまく処理ができない可能性がある。また、Cometを使用する分、ポーリング方式よりも負荷が高くなってしまう。


#最後に
通信方法の理解は早めにしておかないと苦労しそうだったので、まとめてみました。
（もしこの記事に誤りがありましたらご教授いただけると幸いです。）