เมื่อคุณต้องการส่งข้อมูลผ่าน UDP คุณจะพบกับข้อจำกัด: ข้อมูลจะต้องถูกส่งเป็นชิ้นเล็กๆ เพื่อให้พอดีกับ MTU แพ็กเก็ตอาจสูญหายโดยไม่มีการแจ้งเตือน มีการทำซ้ำหรืออยู่ในลำดับที่ไม่ถูกต้อง
uTP (โปรโตคอลการขนส่งขนาดเล็ก) ถูกคิดค้นโดยผู้ใช้ torrent เพื่อส่งไฟล์ผ่าน UDP ได้อย่างปลอดภัย โดยพื้นฐานแล้ว จะเพิ่มคุณสมบัติ TCP ให้กับ UDP: แพ็กเก็ตที่สูญหายจะถูกส่งอีกครั้งโดยอัตโนมัติ รับประกันคำสั่งซื้อ และปฏิเสธรายการที่ซ้ำกัน
ไลบรารีนี้ใช้ uTP ผ่าน UDP ดังนั้นเมื่อเชื่อมต่อแล้ว คุณจะได้รับออบเจ็กต์ ซ็อกเก็ต ซึ่งมีพฤติกรรมเหมือนกับซ็อกเก็ต Node.js tcp เมื่อรับข้อมูลแล้วจะปล่อย 'ข้อมูล' โดยมีเมธอด .write() ให้คุณส่งบัฟเฟอร์ได้ เช่นเดียวกับซ็อกเก็ต TCP นี่คือสตรีม Node.js
อย่างไรก็ตาม ไลบรารีอาจเข้ากันไม่ได้กับการใช้งาน uTP อื่นๆ (ดังนั้นคุณจึงจำเป็นต้องใช้ไลบรารีเดียวกันนี้บนเพียร์ทั้งสอง) เนื่องจากไลบรารีดังกล่าวเพิ่มคุณลักษณะต่อไปนี้: อินสแตนซ์เดียวกันของคลาสสามารถใช้ได้ทั้งเป็นเซิร์ฟเวอร์และ ลูกค้าในเวลาเดียวกันบนพอร์ตเดียวกัน ดังนั้นคุณจึงสามารถสร้างโหนด ผูกเข้ากับพอร์ต และในเวลาเดียวกันก็เริ่มฟังการเชื่อมต่อขาเข้าและทำการเชื่อมต่อขาออกด้วย
npm install --save utp-punch
const Node = require('utp-punch');
let server = new Node(socket => {
console.log('server: socket connected');
socket.on('data', data => {
console.log(`server: received '${data.toString()}'`);
socket.write('world');
socket.end();
});
socket.on('end', () => {
console.log('server: socket disconnected');
server.close(); // this is how you terminate node
});
});
server.bind(20000, '127.0.0.1'); // bind to port 20000
server.listen( // run
() => console.log('server: ready')
);
let client = new Node();
client.bind(); // bind to any port
client.connect(20000, '127.0.0.1', socket => {
console.log('client: socket connected');
socket.on('data', data => console.log(`client: received '${data.toString()}'`));
socket.on('end', () => {
console.log('client: socket disconnected');
client.close(); // this is how you terminate node
});
socket.write('hello');
});
อีกเทคนิคหนึ่งที่ใช้ในที่นี้คือการเจาะรู UDP
เมื่อเซิร์ฟเวอร์และ/หรือไคลเอนต์อยู่หลัง NAT โดยปกติแล้วจะไม่มีที่อยู่ IP อินเทอร์เน็ตที่จะเชื่อมโยงเพื่อรับการเชื่อมต่อขาเข้า
การเจาะรู UDP หลอกให้ไฟร์วอลล์เปิดรูชั่วคราวสำหรับผู้ใช้ ดังนั้นพอร์ตบนอุปกรณ์ NAT จึงถูกผูกไว้กับพอร์ตของเซิร์ฟเวอร์/ไคลเอนต์ภายใน LAN
เพื่อให้ทำงานได้ทั้งเซิร์ฟเวอร์และไคลเอนต์ต้องใช้เซิร์ฟเวอร์บุคคลที่สามเพื่อค้นหาที่อยู่ NATed IP ของกันและกันและประสานความพยายามในการเจาะ (ต้องทำพร้อมกันบนเซิร์ฟเวอร์และบนไคลเอนต์)
แต่เมื่อสร้างการเชื่อมต่อแล้ว เซิร์ฟเวอร์ของบริษัทอื่นก็ไม่จำเป็นอีกต่อไปและไม่เคยถูกใช้เป็นรีเลย์ ข้อมูลทั้งหมดจะถูกส่งโดยตรงระหว่างเซิร์ฟเวอร์ NATed และไคลเอนต์นี้
const Node = require('utp-punch');
let server = new Node();
server.bind(20000);
let client = new Node();
client.bind(30000); // client needs dedicated port
// just as the server
// both server and client must contact a third party server
// which will report their peer NATed address and port to them
let serverAddress, serverPort;
let clientAddress, clientPort;
// up to ten punches:
server.punch(10, clientPort, clientAddress, success => {
// if success is true hole is punched from our side
// nothing to do here as the client will try
// to connect normally when he is also successful
});
client.punch(10, serverPort, serverAddress, success => {
if (success) {
client.connect(serverPort, serverAddress, socket => {
// if the server had also been successful in punching
// this will succeed
});
client.on('timeout', () => {
// if the server had failed in punching we won't be
// able to connect
});
}
});
โปรดดูตัวอย่างการเจาะรูทั้งหมดในไดเร็กทอรี example/
คลาสเดียวกันสามารถใช้เป็นเซิร์ฟเวอร์หรือไคลเอนต์ได้ โดยมีไวยากรณ์ดังนี้:
ตัวเลือก มีดังต่อไปนี้:
{
bufferSize: 64, // number of packets
mtu: 1000, // bytes excluding uTP header
timeout: 5000, // ms
resend: 100, // ms
keepAlive: 1000, // ms
}
onConnection จะถูกส่งผ่านอาร์กิวเมนต์เดียว - ซ็อกเก็ต นี่คือการเชื่อมต่อขาเข้าของเซิร์ฟเวอร์
Getter สำหรับจำนวนการเชื่อมต่อสูงสุดที่โหนดสามารถรองรับได้
Getter สำหรับจำนวนการเชื่อมต่อขาเข้า
Getter สำหรับจำนวนการเชื่อมต่อขาออก
ส่งคืนซ็อกเก็ต UDP Node.js มาตรฐานซึ่งใช้ภายใต้ประทุน
ที่อยู่ที่ถูกผูกไว้ของซ็อกเก็ต (เหมือนกับใน Node.js UDP .address())
ผูกเข้ากับโฮสต์: พอร์ตและดำเนินการ onBound เมื่อเสร็จสิ้น
เริ่มเจาะโฮสต์: พอร์ตและเรียกใช้การติดต่อกลับเมื่อสำเร็จหรือไม่มีความพยายามเหลือเลย ความสำเร็จหรือความล้มเหลวจะถูกส่งผ่านไปยังการโทรกลับเป็นพารามิเตอร์บูลีนตัวแรก
เปลี่ยนโหนดนี้ให้เป็นเซิร์ฟเวอร์และดำเนินการเรียกกลับนี้เมื่อพร้อมที่จะยอมรับการเชื่อมต่อขาเข้า
เชื่อมต่อกับเซิร์ฟเวอร์โหนดบนโฮสต์: พอร์ตและดำเนินการโทรกลับด้วยวัตถุซ็อกเก็ตเป็นพารามิเตอร์เดียว
ยุติการเชื่อมต่อและโหนดทั้งหมด เรียกใช้การโทรกลับ
วัตถุซ็อกเก็ตที่ส่งผ่านไปยังตัวสร้างโหนดและการเรียกกลับ .connect() เป็นกระแสที่ปล่อย 'ข้อมูล' เมื่อรับข้อมูล มันมีวิธีการปกติ: .write(), .end() ฯลฯ
ไลบรารี 'utp' ดั้งเดิมถูกสร้างขึ้นโดย @mafintosh ใน https://github.com/mafintosh/utp นี่คือการเขียนใหม่ใน JavaScript สมัยใหม่พร้อมการแก้ไขข้อบกพร่องและคุณสมบัติเพิ่มเติมรวมถึงการใช้เป็นเซิร์ฟเวอร์และไคลเอนต์พร้อมกันบนพอร์ตเดียวกันและรองรับการเจาะรู UDP