3

TCP 接続を介して n 個のバイトで x 個のパケットを送信するのにかかる時間を測定したいと考えています。唯一の問題は、パケットがマージされていることです。TCPがデフォルトでこれを行うことは知っていますが、パケットをマージしてすぐに送信するにはどうすればよいですか。

クライアント:

var net = require('net');

var HOST = '127.0.0.1';
var PORT = 6969;
var number_packets = 2500;
var packet_size = 200;
var client = new net.Socket();

client.connect(PORT, HOST, function() {
    client.setNoDelay(true);
    for (var i = 0; i <= 100; i++) {
        var message = new Buffer(packet_size);
        console.log('Sending message #: '+i);
        client.write(message);
    }
});

client.on('data', function(data) {    
    console.log('DATA: ' + data);
    // Close the client socket completely
    client.destroy();
});

client.on('close', function() {
    console.log('Connection closed');
});

サーバ:

var net = require('net');

var HOST = '127.0.0.1';
var PORT = 6969;
var count = 1;

net.createServer(function(sock) {
    sock.on('data', function(data) {
        var size = data.length;
        console.log('pkt: '+count+' size: '+size);
        //sock.write(data+'-');
        count++;
    });

    sock.on('close', function(data) {
        console.log('CLOSED: ' + sock.remoteAddress +' '+ sock.remotePort);
    });
}).listen(PORT, HOST);

//console.log('Server listening on ' + HOST +':'+ PORT);
4

1 に答える 1

7

setNoDelaytrueに設定して、コード内の Nagle アルゴリズムを既に無効にしています。あなたが直面している問題は異なります。あなたが直面している問題は、TCP プロトコルにパケットの概念がないことです。

基礎となるプロトコルである IP は、パケットを処理します。TCP は、IP の上に実装された高レベルのストリーム ベースのプロトコルであり、ソフトウェアがファイル記述子の読み取りと書き込みを行っているふりをすることができます。そのため、TCP プロトコルの設計の意図から、パケット境界を無視し、すべてのメッセージを 1 つのストリームにマージします。

問題は小さなメッセージのマージだけでなく、大きなメッセージの分割にもあることに注意してください。送信側、受信側、さらにはルーターやプロキシで発生する可能性があります。TCP メッセージが分割され、マージされる場所を実際に制御することはできません。

メッセージがどこで終了するかを正確に知りたい場合は、TCP に加えて別のプロトコルを使用する必要があります。簡単な例の 1 つが HTTP です。

HTTP 1.0 以前では、パケットの終了を通知するための非常に単純な条件が実装されています。つまり、接続を閉じるだけです。HTTP 1.0 パケットの構造は次のとおりです。

HTTP/version status (200 for OK) comment (human readable meaning of status code)
headers (note, commands and headers are separated by newlines (\n)) 
headers
headers
two newlines (\n) indicates end of headers:

data
data
data
connection closed indicating end of data

HTTP 1.1 では、Content-Lengthヘッダーを追加することでこれが改善されました。これにより、HTTP 1.1 は接続ごとに複数の「パケット」 (html ファイル、gif 画像など) を送信できます。したがって、HTTP 1.1 は次のようになります。

HTTP/version status comment
headers
Content-length: number of bytes in the data section
headers

data
data
end of data
HTTP/version status comment (beginning of second packet)
headers
Content-length: number of bytes in the data section
headers

data
data
end of data

これは、TCP 上で動作する最も単純なプロトコルの 1 つです。しかし、コンテンツの長さの概念は、はるかに古いプロトコルから来ています。IP 自体に長さフィールドがあります。イーサネット フレームも同様です。同じアイデアを使用して、タスクに簡単なプロトコルを実装できます。

[  len   ][  len   ][  data  ][  data  ][  data  ] ...
     \________/         \____________________/
         |                        |
         |                        |
         |                "length" bytes of data
         |
   two bytes indicating length of packet

または、HTTP のように改行を区切り文字として使用するというアイデアを借りることもできます。これには、プロトコルがほとんどテキストベースであるため、javascript での処理が容易になるという利点があります。

data data data data data data\n
   \___________________/      |
             |                |
             |           end of packet
             |
  data section (must not contain newlines)

データに改行を含める必要がある場合は、JSON で処理される方法で処理できます。「\」の後に「n」を送信します (つまり、「\n」エスケープ シーケンスを実装します)。区切り文字として何でも選択できることに注意してください。改行である必要はありません。

コンセプトを混在させることもできます。これは私が数年前に開発したテキスト ベースのプロトコルですが、バイナリ プロトコルからの長さプレフィックスのアイデアを使用しています。

12345;data data data data ...
  |  |
  |  |____ semicolon indicates start of data section
  |
  |
 length of data section sent as an ASCII string

もちろん、最良の方法は、他の人が既に考案し、node.js に実装したプロトコルを使用することです。これにより、車輪を再発明する必要がなくなります。ノードにはHTTPも組み込まれています。あなたの目的のために、HTTPはヘッダーに数百バイトのオーバーヘッドを追加することを理解していますが、これを説明するのは困難です。オーバーヘッドの少ないプロトコルが必要な場合は、常に FTP があります。また、npm にはいくつかの実装があります。

于 2012-11-20T05:07:33.480 に答える