WebSocketを理解していませんか?この記事では、WebSocketの原理を完全に理解することができます

WebSocketビデオ分析について:

WebSocketプロトコル、tcp下請けおよびスティッキーパッケージソリューション、
大企業のインタビュー手法、およびWebSocketプロトコルの使用シナリオと実装スキームに関する詳細な説明

まず、websocketの背景を見てみましょう。httpシリーズプロトコルはtcpに基づいて構築されていることがわかっています。理論的には、双方向で通信できます。しかし、http1.1より前は、サーバーはプッシュ機能を実装していませんでした。それがクライアント要求であり、サーバーが応答するたび。リクエスト処理時のHTTPプロトコルの開発を見てみましょう。

  1. http1.0では、http要求のライフサイクルは、クライアントが要求を開始し、サーバーが応答し、接続が切断されることです。しかし、tcpプロトコルの欠点は、スロースタートやその他の特性と相まって、スリーウェイハンドシェイクに時間がかかることです。すべてのhttpリクエストがこのような場合、効率は非常に低くなります。
  2. http1.1では、長い接続がデフォルトで有効になっています(キープアライブヘッダーはクライアント要求で設定されます)。サーバーは要求を処理した後、接続をすぐに閉じませんが、一定時間待機します。リクエストがない場合、接続は閉じられます。このようにして、ブラウザーはtcp接続で要求を継続的に送信できるだけでなく(サーバーは接続で処理できる要求しきい値も制限します)、一度に多くの要求を送信することもできます。これはhttp1.1のパイプライン技術です。しかし、httpプロトコルに基づくクライアントの場合、多くの要求を送信できますが、要求が戻ってきたときに、どの要求が属しているのかわからないため、彼にも問題があります。したがって、返されたパケットは要求された順序でしか返されません。これは、別の問題であるリンクヘッドブロッキングにつながります。また、http1.1は長い接続をサポートしていますが、サーバーがプッシュ(プッシュ)する機能はサポートしていません。サーバーにクライアントに提供するデータがある場合、サーバーはクライアントがデータをフェッチする(プルする)のを待つことしかできません。
  3. http2.0に関しては、サーバープッシュが実現されるだけでなく、フレーム(iframe)やストリーム(ストリーム)などのテクノロジーを使用してスレッドブロッキングの問題を解決します。tcp接続では、http2.0は複数を送信できます。 httpリクエストを同時に。各リクエストはストリームであり、ストリームは多くのフレームに分割できます。タグ番号を使用すると、サーバーはパケットを自由に送り返すことができます。クライアントはそれを受信した後、に従って再構築できます。タグ。

上記はリクエストに関するhttpプロトコルのいくつかの開発であり、websocketはサーバープッシュのための別のソリューションを提供します。これは本質的に、tcpプロトコルにカプセル化された別のアプリケーション層プロトコル(websocketプロトコル)です。これはtcpに基づいているため、サーバー側のプッシュは当然問題になりません。ただし、実装に関しては、彼はtcp接続に直接接続せず、WebSocketプロトコルに基づいてデータパケットを送信します。彼はプロトコルのアップグレード(交換)プロセスを含みます。このプロセスを見てみましょう。

1クライアントはプロトコルアップグレードの要求を送信します。次のhttpヘッダーをhttpリクエストに追加します

Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: k1kbxGRqGIBD5Y/LdIFwGQ==
Sec-WebSocket-Version: 13
Upgrade: websocket

2サーバーがWebSocketプロトコルをサポートしている場合、101ステータスコードを返し、プロトコルのアップグレードに同意し、さまざまな構成をサポートしていることを示します(サーバーが特定の機能やバージョンをサポートしていない場合、またはクライアントが送信できることをクライアントに通知する場合)再度プロトコルアップグレードリクエスト)。サービスは次のhttpヘッダーを返します(websocketプロトコルを参照)。

Connection: Upgrade
Sec-WebSocket-Accept: y73KZR4t+hqD6KKYbkx2tULfBsQ=
Upgrade: websocket

3これでプロトコルのアップグレードが完了します。後続のデータ通信はtcp接続に基づいており、WebSocketプロトコルによってカプセル化されたデータパケットを使用します。

このプロセスをwiresharkで理解しましょう。まず、サーバーを起動します(ip:192.168.8.226)。

var http = require('http');
var fs = require('fs');
const WebSocket = require('ws');
// 如果在浏览器控制台进行测试,可以不起http服务器
const server = http.createServer(options,function(req,res){
    
    
    res.end(fs.readFileSync(`${
    
    __dirname}/websocket.html`));
}).listen(11111);

const wss = new WebSocket.Server({
    
     server }); 
wss.on('connection', function connection(ws) {
    
    
  ws.on('message', function(message) {
    
    
    ws.send(message);
  });

  ws.send('get it');
});

[記事のメリット] C / C ++ Linuxサーバーアーキテクトの学習資料とグループ812855908(C / C ++、Linux、golangテクノロジー、Nginx、ZeroMQ、MySQL、Redis、fastdfs、MongoDB、ZK、ストリーミングメディア、CDN、P2P、K8S、 Docker、TCP / IP、coroutine、DPDK、ffmpegなど)
ここに画像の説明を挿入

ブラウザコンソールで直接テストできます

var ws = new WebSocket("ws://192.168.8.226:11111");
// 连接上后执行
ws.send(11)

このとき、wiresharkパッケージを見てみましょう。

ここに画像の説明を挿入

最初の3つのレコードを最初に見てください。これは、TCPスリーウェイハンドシェイクのデータパケットです。私たちは皆これを理解しているので、それを示しません。次に、4番目のレコードを見てください。展開は次のとおりです。
ここに画像の説明を挿入

tcp接続が確立された後、ブラウザがいくつかのWebSocketデータパケットを含むhttpリクエストを送信したことがわかりました。次に、次のものを見てください。

ここに画像の説明を挿入

サービスは、アップグレード契約または交換契約の契約を返しました。サーバーコードから、接続を確立するときにgetit文字列をブラウザにプッシュすることがわかります。上記の記録を引き続き表示します。

ここに画像の説明を挿入

これは、サーバーがブラウザーにプッシュするWebSocketプロトコルベースのデータパケットです。各フィールドの具体的な意味については、websocketプロトコルを参照してください。レコードを見下ろし続けると、サーバーによってプッシュされたデータパケットのTCPACKになります。最後に、キープアライブを使用して最後の3つのレコードを確認できます。これは、前の記事で説明したtcpレイヤーのキープアライブです。データ送信がないため、tcpレイヤーはプローブパケットを断続的に送信します。プローブパケットの構造を見ることができます。

ここに画像の説明を挿入

1バイトのプローブデータがあります。この時点でサーバーにデータパケットを送信するとどうなりますか?

ここに画像の説明を挿入

白い背景の3つのデータは、ブラウザーからサーバーに送信されたデータと、サーバーによってプッシュバックされたデータです。tcpack。サーバーがブラウザーにプッシュすると、ブラウザーはackを送信しますが、ブラウザーがサーバーに送信すると、サーバーはackを返さないように見えることがわかりました。理由を見てみましょう。まず、ブラウザから送信されたパッケージを確認します。

ここに画像の説明を挿入

サーバーがブラウザにプッシュするデータパケットを確認します。

ここに画像の説明を挿入

サーバー(tcp)がメッセージをプッシュすると、ackも発生することがわかりました。2つのtcpパケットを送信する代わりに。これがtcpのメカニズムです。TCPは、すべてのパケットにackを送信するわけではありません。ネットワークパケットを減らすために確認応答を蓄積します(ackを送信します)が、できるだけ早くackに応答する必要があります。そうしないと、クライアントがタイムアウトの再送信をトリガーします。 。tcpはいつ確認を送信しますか?たとえば、データを送信する必要がある場合、一定期間データパケットを受信しない場合、または確認の累積数がしきい値に達した場合などです。tcpについて学習したので、さらに調査することもできます。この時点でサーバーがシャットダウンされた場合にどうなるかを見てみましょう。

ここに画像の説明を挿入

サーバーはリセットパケットをブラウザに送信し、切断する必要があることを通知します。続けて、ブラウザ自体が接続を閉じるためにcloseを呼び出した場合はどうなりますか。

ここに画像の説明を挿入

WebSocketが最初にFINパケットをサーバーに送信し、次にサーバーがFINパケットを返し、次に実際の4つのウェーブハンドを開始することがわかります。そして、4回振られた最初のfinパッケージがサーバーから送信されました。

WebSocketの安全なバージョンを見てみましょう。httpsサーバーを起動します。

var https = require('https');
var fs = require('fs');
const WebSocket = require('ws');

var options = {
    
    
    key: fs.readFileSync('./server-key.pem'),
    ca: [fs.readFileSync('./ca-cert.pem')],
    cert: fs.readFileSync('./server-cert.pem')
};

const server = https.createServer(options,function(req,res){
    
    
    res.end(fs.readFileSync(`${
    
    __dirname}/websocket.html`));
}).listen(11111);

const wss = new WebSocket.Server({
    
     server });

wss.on('connection', function connection(ws) {
    
    
  ws.on('message', function(message) {
    
    
    ws.send(message);
  });
});

次に、ブラウザコンソールで実行します。

var ws = new WebSocket("wss://192.168.8.226:11111");
ws.sned(11);

次に、wiresharkを見てください。

ここに画像の説明を挿入

最初にtcp接続を確立し、次にtls接続を確立します。後続のデータ通信は、暗号化に基づいて実行できます。繰り返さないでください。後でtlsプロトコルを分析します。

一連の分析の後、WebSocketプロトコルをよりよく理解し、最後にWebSocketについてのポイントについて話し合う必要があります。WebSocket接続で通信がない場合、WebSocket接続が維持される時間はtcpに依存することがわかりました。tcp層は常にプローブパケットを送信することがわかったためです。しきい値に達すると、接続が切断されます。したがって、WebSocket接続を維持したい場合は、pingやpongなどのハートビートパケットを自分で送信する必要があります。

公式アカウントに注意を払い、興味のあるインターネット技術コンテンツをもっと共有してください!ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/qq_40989769/article/details/111316270