54657


2chやLINEなど、現在では非同期送信や受信が当たり前のように使われています。非同期送信はすごくわかりやすいのですが、非同期受信の仕組みがよくわかりません。

例えば2ch見ている時に非同期受信ができる理由は、

  * サーバーが繫がっている端末のアドレスを保存していてそこに向けて何か変化があれば送信している

ということですか？それならすごくサーバーの処理が重くなるとおもうのですが。

予想としては、

  * クライアント→サーバーへの流れのようにサーバー側でクライアントのURLを保存しておきそこへデータを送っている。

サーバー通信の仕組みがいまいちわかりません。  
クライアント→サーバーへはURLで送信するのはわかりますが、そのURLアクセスから返す方法や、非同期でサーバーからクライアントへデータを転送する方法がわかりません。


CC BY-SA 4.0
2019-05-02T06:24:17.597
54646
2019-05-02T12:55:53.760
2019-05-02T11:08:02.473
29826
31135
question
ajax 非同期 サーバー管理
チャットの非同期通信について


_ここで想定されている技術は **非同期通信** ではなく **双方向通信** 、特にサーバからクライアントへの **Push**
が適切なようです。また、通信の方法全体に渡って記述すると範囲が広く、IPマスカレードなどの低レイヤの話も含む必要が出てくるので、TCP/IPより上の技術にのみ絞って回答します。また、双方向通信においてもサーバ-
クライアント間のみならず、クライアント-
クライアントのようなP2P通信なども話題がありますが、これらは質問から外れるため割愛します（これらの話が必要であれば別途新しく質問をしてください）。_

[Push技術 - Wikipedia](https://ja.wikipedia.org/wiki/Push%E6%8A%80%E8%A1%93)

# ポーリング

さて、チャットなどのサービスにおいて新しい情報がないか取得するための方法は昔から試行錯誤されており、最初は **ポーリング**
と呼ばれる手法が一般的でした。これは、クライアント側が「情報が更新されていないか？」と定期的にサーバに対してHTTPリクエストを行うものです。これは、バニラJavascriptのみで実装可能でしたが、以下のようなデメリットがありました。

  * 毎回HTTP接続を貼り直さなければならない
  * ポーリングの頻度が高いとサーバへの負荷が高まり、頻度が低いとリアルタイム性が損なわれる 
    * 更新間隔はポーリングの頻度と直結してしまう

# Comet

そこで、後者の問題を解決するため、 **Comet** という概念が提唱されました。これは、Long-time
Pollingとも呼ばれ、基本的にはポーリングと同じですが「サーバ側でリクエストを保持し、更新情報が発生したらレスポンスを返す（それまで通信を持ち続ける）」という点が特徴です。この結果、新しいデータが来るまでの更新は防げるためサーバへの負荷は抑えられましたが、以下のようなデメリットがありました。また、HTTP接続はポーリング同様リクエストの度に発生しました。

  * 真のリアルタイムではない 
    * サーバからレスポンスが返ってきてから新しいリクエストを送るまでの間はリアルタイムではない
    * 短期間に複数の新しいデータを送信するのに不向き
  * サーバ側で接続を保持する必要があり、負荷へつながる

[Comet (programming) -
Wikipedia](https://en.wikipedia.org/wiki/Comet_%28programming%29)

# Server-Sent Events (SSE)

ポーリング、Cometは素のJavascriptでも実装可能な分、仕組みはシンプルなものでした。しかし、毎回HTTPコネクションを貼り直すという点、リアルタイム性が低い点という問題がありました。そこで提案されたのが
**Server-Sent Events** で、これはHTTP接続は保持したまま、レスポンスを `chunked`
という分割されたデータとして返すという方式です。接続を貼り直す必要がなく、かつ真にリアルタイムな通信を行うことができるようになりました。また、あくまでもHTTPの仕様に基づいたものであるということもメリットの一つでした。これはW3Cの仕様になり、Google
Chromeではバージョン6（2010年リリース）からサポートされているようです。

  * HTTPヘッダをレスポンスに付加する必要がある 
    * ポーリングよりは軽量だが、不要なデータであり、大量の通信をする場合には大きな差が出る
  * ブラウザがサポートする必要がある 
    * なお、2019年現在では全ての主要ブラウザでサポートされています

[Server-Sent Events の利用 - Server-sent events |
MDN](https://developer.mozilla.org/ja/docs/Server-sent_events/Using_server-
sent_events)  
[Server-sent events - Wikipedia](https://en.wikipedia.org/wiki/Server-
sent_events)

# WebSocket

さて、ここまでの技術はあくまでもHTTPという規格に基づいたものでした。このため、ここまでで洗練されたServer-Sent
Eventsでも、毎回HTTPヘッダを通信の度に送る必要があり、頻度や規模によっては大きい負荷となりました。また、HTTP通信の仕様上、同時接続数などの制限も存在しました。そこで生み出されたのが
**WebSocket** です。

これは、Unixにおけるソケット通信をTCP/IPの上で行うようなイメージであり、サーバ-
クライアント間の通信のために生み出されたHTTPとは別の規格です。HTTP通信におけるデメリットがなくなり、また、既にW3Cで標準化済みであり、現代における最も標準的な方法と言えるでしょう。以下の通りデメリットは存在しますが、Secure
Websocketを使えば問題ありません。

  * HTTPに基づいたものではない 
    * ブラウザ及びサーバがサポートする必要がある
    * なお、2019年現在では全ての主要ブラウザでサポートされています
  * 怪しい通信としてブロックされる場合がある 
    * Secure Websocket(WSS)を使えば通信の内容が暗号化されるため、問題ない

### 参考文献

[サーバPUSHざっくりまとめ](https://www.slideshare.net/mawarimichi/push-37869433)  
[リアルタイム通信で利用されるプロトコルと手法 -
tech.guitarrapc.cóm](https://tech.guitarrapc.com/entry/2015/08/17/044937)  
[リアルタイムなwebアプリを実現する方法(ポーリング、Comet、Server Sent Events、WebSocket) -
Qiita](https://qiita.com/kimullaa/items/d49bd603be17b36f7495)


CC BY-SA 4.0
2019-05-02T12:40:55.323
54657
2019-05-02T12:55:53.760
2019-05-02T12:55:53.760
29826
29826
54646
answer