我有两个正在互相交谈的进程-客户端是一个C#控制台应用程序。该服务器是一个使用“ net”模块(TCP)的Node.js应用。
我需要完成的过程是:
此操作正常进行,直到,步骤1中的有效负载达到一定大小。那时,数据开始被拆分为多个块。块的总大小等于最初发送的有效负载,因此它们全部到达了服务器。
这会导致问题,因为产生PDF的代码在socket.on(data)
事件中。由于多次接收到数据,因此服务器正在创建多个PDF,但它们都不完整。
我读过的一些帖子建议使用socket.on(end)
事件,但是由于未关闭连接而未触发该事件-我需要保持连接打开状态才能执行步骤3。
我的第一个想法是“我需要增加缓冲区大小,以便发送整个文件”,但是在进行了一些研究之后,我决定反对这一做法,因为似乎拆分数据是预期的行为。
我的问题是:我怎么知道整个有效负载何时到达Node.js服务器?
data
对象上是否有一个属性?看来这肯定是常见的情况,所以我正在寻找一些最佳实践,因为我对Node.js相对较新。
更新
这是(缩写)代码,由于多次接收数据,导致创建多个PDF:
const net = require('net');
const PORT = 8080;
const ADDRESS = '127.0.0.1';
const server = net.createServer(onConnectionOpen);
server.listen(PORT, ADDRESS);
function onConnectionOpen(socket) {
socket.on('data', (data) => {
const folderName = 'reports';
var fileName = functions.getRandomString(50) + '.pdf';
var fullPath = process.cwd() + '\\' + folderName + '\\' + fileName;
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.setContent(data.toString());
const pdf = await page.pdf({ path: fullPath, format: 'Letter' });
console.log('Total bytes returned: ' + pdf.length);
socket.write(pdf);
await browser.close();
})();
})
socket.on('end', () => {
socket.destroy();
})
}
我曾尝试将Puppeteer和socket.write(...)
移至socket.on('end')
,但是由于连接仍处于打开状态,因此在生成PDF之后该代码无法运行。
答案 0 :(得分:0)
将在socket.on(data)处理程序中接收到的任何单个块的数据追加到与条件data.toString()。toLowerCase()。endsWith(“”);匹配的块中。
如果有效负载为html,则应该可以使用。有效负载的末尾只有定界符,就可以使用它。
答案 1 :(得分:0)
如果发送方在完成发送后不打算关闭套接字,那么您必须通过读取数据中的内容来告知发送完成的时间。有很多方法可以做到这一点。例如,您可以将其编码为MIME部分,该部分的开头和结尾都有唯一的标记,您可以在阅读时注意这些标记。
由于您已经说过内容是HTML,可以控制另一端的发送,因此您可以仅在HTML末尾使用结尾</html>
作为分隔符。要以一种简单的方式执行此操作,您必须确保主文档中没有任何嵌入式HTML文档(例如具有本地内容的iframe)。如果可以做出这些假设,则可以将对</html>
的检测用作定界符,以告诉您何时完成HTML的接收。
通过这些简化的假设,您可以像这样检测到这一点:
const net = require('net');
const PORT = 8080;
const ADDRESS = '127.0.0.1';
const puppeteer = require('puppeteer');
const server = net.createServer(onConnectionOpen);
server.listen(PORT, ADDRESS);
function onConnectionOpen(socket) {
let receivedData = "";
socket.on('data', (data) => {
receivedData += data.toString();
// if we have the ending tag of our HTML, then process it
let html = receivedData;
if (html.indexOf("</html>") !== -1) {
// reset receivedData so if any more data arrives (after the </html>)
// it won't affect the html string we now have locally
receivedData = "";
const folderName = 'reports';
const fileName = functions.getRandomString(50) + '.pdf';
const fullPath = process.cwd() + '\\' + folderName + '\\' + fileName;
(async () => {
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.setContent(html);
const pdf = await page.pdf({ path: fullPath, format: 'Letter' });
console.log('Total bytes returned: ' + pdf.length);
socket.write(pdf);
await browser.close();
})().catch(err => {
// handle error here
});
}
});
socket.on('end', () => {
socket.destroy();
});
}
如果可以嵌入HTML文档,则需要更多的代码才能知道何时有了外部</html>
。而且,如果不确定</html>
是否为小写,则也必须进行不区分大小写的搜索。
如果您甚至无法保证HTML内容的末尾有一个</html>
,那么您需要以某种方式确保末尾有一些已知的定界符,否则您必须先发送长度为内容,以便您知道何时拥有所有数据。只是没有其他方法可以知道内容的结尾在哪里。