2017-09-04 97 views
0

我有很多設備將消息發送到寫入節點的TCP服務器。 TCP服務器的主要任務是將一些消息路由到redis以便被另一個應用程序處理。node.js使用TCP服務器傳輸和保存文件

我寫了一個簡單的服務器,很好地完成了這項工作。代碼的結構基本上是這樣(不是實際的代碼,細節隱藏):

const net = require("net"); 

net.createServer(socket => { 
    socket.on("data", buffer => { 
    const data = buffer.toString(); 
    if (shouldRouteMessage(data)) { 
     redis.publish(data); 
    } 
    }); 
}); 

大多數消息是這樣的:{"text":"message body"},或{"lng":32.45,"lat":12.32}。但有時我需要處理一個消息,如跨越幾個「數據」事件的消息,如{"audio":"...encoded audio..."}

在這種情況下,我需要將編碼後的音頻保存到文件中,併發送到redis {"audio":"path/to/audio-file.mp3"},其中路由是接收到音頻數據的文件。

一個簡單的選擇是存儲緩衝區,直到檢測到消息結束並將其全部保存到文件中,但這意味着,除了別的以外,我必須在保存到磁盤之前將文件保留在內存中。

我希望有更好的選擇,使用流和管道。有什麼建議麼? (一些代碼示例,將是很好的)

感謝

回答

0

我終於解決了,所以我在這裏發佈的解決方案以作記錄(以及一些運氣,幫助他人)。

解決方案確實非常簡單:只需打開一個寫入流到一個文件並在數據包被接收時寫入數據包。事情是這樣的:

const net = require("net"); 
const fs = require("fs"); 

net.createServer(socket => { 
    socket.on("data", buffer => { 
    let file = null; 
    let filePath = null; 
    const data = buffer.toString(); 

    if (shouldRouteMessage(data)) { 
     // just publish the message 
     redis.publish(data); 
    } else if (isAudioStart(data)) { 
     // create a write stream to a file and write the first data packet 
     filePath = buildFilePath(data); 
     file = fs.createWriteStream(filePath); 
     file.write(data); 
    } else if (isLastFragment(data)) { 
     // if is the last fragment, write it, close the file and publish the result 
     file.write(data); 
     file.close(); 
     redis.publish(filePath); 
     file = filePath = null; 
    } else if (isDataFragment(data)) { 
     // just write (stream) it to file 
     file.write(data); 
    } 
    }); 
}); 

注:shouldRouteMessagebuildFilePathisDataFragment,並isLastFragment是依賴於數據的類型的自定義功能。

通過這種方式,輸入數據是直接流到文件並且不需要將內容保存在內存之前。節點的溪流岩石!

一如既往的惡魔在細節中。例如,一些檢查是必要的,例如,確保在您要寫入文件時始終有一個文件。還記得轉換爲字符串時設置正確的編碼(例如:buffer.toString('binary');爲我做了詭計)。根據您的數據格式,shouldRouteMessageisAudioStart ...以及所有這些自定義功能可能更復雜或更簡單。

希望它有幫助。

相關問題