2017-01-12 3 views
0

ソケット上で送信されるバイナリデータの簡単なテストを設定しています。バッファを渡して渡すときにnodejsソケットが奇妙に動作する

送信側では、呼び出しに渡された引数の数を単純にエンコードし、次に各引数について、その引数の長さをエンコードします。これは私に様々なバイナリデータを送信してテストするために迅速かつ簡単な方法を提供します:受信側では

var client = new net.Socket() 
client.connect(9999, host, function() { 
    console.log("Connected") 
    // convert argument list into length delimited parameters 
    var i,args = process.argv.length-3 
    var buf = new Buffer(4) 
    buf.writeInt32LE(args,0) 
    client.write(buf) 
    console.log("sending "+args+" args") 
    for (i=3;i<args+3;i++) { 
     console.log("["+(i-3)+"] "+process.argv[i].length) 
     buf.writeInt32LE(process.argv[i].length) 
     client.write(buf) 
    } 
    client.end()  
}) 

私は余分な引数の数が、その後、各引数のために、私はその引数の長さを抽出し、全部を印刷します。私は小さなステートマシンを使って、私が読んでいる場所を把握しています。私は見てい

var server = net.createServer(function(x) { 
    console.log("connected") 
    var state=0,args,argn 
    x.on("readable",function() { 
     switch (state) { 
     case 0: 
      var n = x.read(4) 
      console.log("[0]"); console.dir(n) 
      if (n === null) return 
      args=n.readInt32LE(0) 
      console.log(args+" arguments") 
      state = 1 ; argn = 0 
      break 
     case 1: 
      var n = x.read(4) 
      console.log("[1]"); console.dir(n) 
      if (n === null) return 
      console.log("argument "+argn+" has "+n.readInt32LE(0)+" bytes") 
      if (++argn > args) { 
       console.log("end of arguments") 
       state = 0 
      } 
      break 
     default: 
      console.log("state="+state+", now what?") 
    } 
}) 
x.on("close",function() { console.log("closed") }) 
x.on("end",function() { console.log("ended") }) 

server.listen({port:9999}) 

問題は、私は最後の二つの引数の長さ(32ビット整数)を受けるように見えることはありませんということです。私は送信側で1つまたは2つの追加の整数を送信してみましたが、違いがあるかどうかを確認しましたが、そうではありません。 の可読性のあるコールバックは、これまで想定されていた回数だけ呼び出されることはありません。例えば

、クライアント側で私が起動する場合:

node tcptest.js tx "Hello world" 12345 AAA 9 

クライアント側の出力は次のようになります。

sending 
Connected 
sending 4 args 
[0] 10 
[1] 5 
[2] 3 
[3] 1 
Connection closed 

しかし、サーバ側で、私が見るすべては次のとおりです。

receiving 
connected 
[0] 
Buffer [ 4, 0, 0, 0 ] 
4 arguments 
[1] 
Buffer [ 10, 0, 0, 0 ] 
argument 0 has 10 bytes 
[1] 
Buffer [ 5, 0, 0, 0 ] 
argument 1 has 5 bytes 
socket ended 
socket closed 

私はbufオブジェクトを再利用しようとしませんでしたが、しばらく働いていましたが、間欠的にもう一度失敗する。それはしばらくの間、再び仕事を始めたとき

... 
for (i=3;i<args+3;i++) { 
    buf = new Buffer(4) 
    console.log("["+(i-3)+"] "+process.argv[i].length) 
... 

は、私は多分書くために渡すために再利用されることからバッファを許可されていない文書化されていない何かがあったと思ったが、今私は知りません。バッファをまったく使用しない場合ソケットにstdinをパイプするとうまくいきますが、このようなバイナリデータを構築しようとすると必ず受け取られるわけではありません。

私は間違っていますか?

更新: サーバー側でread()を呼び出してバイト数を指定するのではなく、受信したすべてのデータが表示されます。私は何が起きているのだろうと思うのは、利用可能なバイト数よりも少ないバイト数を読み込んだ場合、私は追加のコールバックを取得しないということです。

+0

あなただけのソケット 'のようなものをやってみました。 pipe(decrypter).pipe(process.stdout) 'サーバー上で? – idbehold

+0

@ idbeholdええ、それは(クライアントを除いて)作品に似ています。私は質問を書き直しました...暗号化とはまったく関係がなく、バッファオブジェクトを再利用することとは何も関係がないようです – Michael

答えて

0

「読み取り可能な」イベントは、受信された追加のデータごとに1回だけ発生します。上記のコードは、利用可能なすべてのデータが読み込まれていない場合、返されたときに再び呼び出されることを前提としていますが、これは当てはまりません。

次のコードは、それが次の期待のチャンクを取得することはできませんになるまでデータを引っ張り続けるループ状態マシンをラップすることにより、問題が修正されています。

x.on("readable",function() { 
    while (true) { 
     switch (state) { 
     case 0: 
      var n = x.read(4) 
      console.log("[0]"); console.dir(n) 
      if (n === null) return 
      args=n.readInt32LE(0) 
      console.log(args+" arguments") 
      state = 1 ; argn = 0 
      break 
     case 1: 
      var n = x.read(4) 
      console.log("[1]"); console.dir(n) 
      if (n === null) return 
      console.log("argument "+argn+" has "+n.readInt32LE(0)+" bytes") 
      if (++argn > args) { 
       console.log("end of arguments") 
       state = 0 
      } 
      break 
     default: 
      console.log("state="+state+", now what?") 
      return 
    } 
} 
関連する問題