Node.jsでTCP通信
Node.jsのnetライブラリを使ったTCP通信プログラムの開発で、イベントの意味を間違えていたので覚書をしておきます。
バイナリデータの扱うときはnetライブラリではできないのかと思いましたが、ただの私の勘違いでした。
ちなみに初めは Socket.IO で実現できるのかと思いましたが、これはWebSocket用なので、純粋なTCP通信には利用できないようです。
勘違いしていたところ
通信時のイベントとして、connection, data, end, close などがありますが、dataとendの意味を間違えていました。
- data
- データを受信するごとに、このコールバックが実行される。
- end
- すべてのデータが受信されたときに、このコールバックが実行される。
実際は、一度にすべてのデータを受け取れるわけではなく、複数回に分けてdataイベントでデータを受信する場合がありました。
その後、データを受信しきるか、クライアント側が切断したときにendイベントが発生しました。
(発生しました、というか私が仕様を間違って理解しただけ。)
正しい扱いかた
データは複数回に分けて受信することがあるので、
- dataイベントでは最後のデータが来るまで受信したデータを連結して保存しておく。
- データを受信しおわるとendイベントが発生する。
データ終了を表すコードがある場合は、
- dataイベントでチェックする。
- 終了コードを受信した場合、クライアント側に返すコードがあれば送信。
- 通信が終了するとendイベントが発生する。
'use strict'; let net = require('net'); const EOF = 0x04; //EOT const ACK = 0x06; //ACK const LISTEN_PORT = 9000; const server = net.createServer(); let counter=0; server.on('connection', (socket)=>{ socket.setEncoding('utf8'); counter++; console.log(`Client connected [${counter}] \n`); let data = ''; socket.on('data', (chunk)=>{ console.log(`Data [${counter}]: ${chunk.length}`); data += chunk; let eof = chunk[chunk.length-1].charCodeAt(0); if (eof===EOT) { console.log(`Send ACK [${counter}]`); let buf = new Buffer.alloc(1); buf.writeInt8(ACK); socket.write(buf); } }); socket.on('end', ()=>{ console.log(`End [${counter}]`); console.log(data); }) socket.on('close', ()=>{ console.log(`Close [${counter}]\n`); }) }); server.listen(LISTEN_PORT, ()=>{ console.log('Server start.'); });