عندما تحتاج إلى نقل البيانات عبر UDP فإنك تواجه حدوده: يجب إرسال البيانات في أجزاء صغيرة لتناسب وحدة الإرسال الكبرى (MTU)، وقد يتم فقدان الحزم بدون إشعار، أو قد تكون مكررة أو بترتيب خاطئ.
تم اختراع uTP (بروتوكول النقل الصغير) بواسطة مستخدمي التورنت لنقل الملفات بأمان عبر 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 مرتبطًا بمنفذ الخادم/العميل داخل الشبكة المحلية.
لكي يعمل كل من الخادم والعميل، يجب عليهم استخدام خادم طرف ثالث لاكتشاف عناوين IP الخاصة بـ NATed لبعضهم البعض ولتنسيق محاولة التثقيب (يجب أن يتم ذلك في وقت واحد على الخادم والعميل).
ولكن عندما يتم إنشاء الاتصال، لم تعد هناك حاجة إلى خادم الطرف الثالث ولا يتم استخدامه مطلقًا كمرحل، حيث يتم نقل جميع البيانات مباشرة بين خادم 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
});
}
});
يرجى الاطلاع على المثال الكامل لثقب الثقب في المثال/ الدليل.
يمكن استخدام نفس الفئة كخادم أو كعميل، بناء الجملة كما يلي:
الخيارات هي التالية:
{
bufferSize: 64, // number of packets
mtu: 1000, // bytes excluding uTP header
timeout: 5000, // ms
resend: 100, // ms
keepAlive: 1000, // ms
}
سيتم تمرير onConnection وسيطة واحدة - المقبس. هذه هي الاتصالات الواردة للخادم
Getter لأقصى عدد من الاتصالات التي يمكن للعقدة التعامل معها
Getter لعدد الاتصالات الواردة
Getter لعدد الاتصالات الصادرة
يُرجع مقبس Node.js UDP القياسي الذي يُستخدم أسفل الغطاء.
العنوان المنضم للمقبس (كما هو الحال في Node.js UDP .address())
ربط بالمضيف: المنفذ وتنفيذ onBound عند الانتهاء
ابدأ في تثقيب المحاولات إلى المضيف: المنفذ وتشغيل رد الاتصال عندما تكون المحاولات ناجحة أو لا توجد محاولات متبقية. يتم تمرير النجاح أو الفشل إلى رد الاتصال باعتباره المعلمة المنطقية الأولى
قم بتحويل هذه العقدة إلى خادم وتنفيذ رد الاتصال هذا عندما تكون جاهزًا لقبول الاتصالات الواردة
اتصل بعقدة الخادم على المضيف: المنفذ وقم بتنفيذ رد الاتصال باستخدام كائن المقبس كمعلمة واحدة
قم بإنهاء جميع الاتصالات والعقدة، وقم بتشغيل رد الاتصال.
كائن المقبس الذي تم تمريره إلى منشئ العقدة وعمليات رد الاتصال .connect() عبارة عن دفق يصدر "بيانات" عند تلقي البيانات. لديه الطرق المعتادة: .write()، .end()، إلخ.
تم إنشاء مكتبة "utp" الأصلية بواسطةmafintosh في https://github.com/mafintosh/utp. هذه إعادة كتابة بلغة JavaScript الحديثة مع إصلاح الأخطاء وميزات إضافية بما في ذلك الاستخدام كخادم وعميل في نفس الوقت على نفس المنفذ ودعم ثقب UDP.