Node.JS中UDP打洞穿透內網路由,架設內網服務器技術詳解及源碼
在制作一款私有云網絡存儲產品時,很多客戶反應,他們希望能遠程訪問。遠程訪問內網服務器成本最低的方式應該就是P2P內網穿透了,這里介紹一下實現原理。
UDP穿透原理
打洞主要采用的是udp的無面向連接的特性來實現,同過user1連接server,打通user1的對外ip和端口,然后在一段時間內server都能通過這個端口和IP實現路由穿透,向局域網內的服務器發送消息。
此時user2連接server,打通uer2對外的ip和端口,然后user1和user2通過彼此已經打通的對外ip和端口實現通訊。
這就是P2P不同網絡間通信協議的基礎。
為了簡單起見,這只僅演示從 user1 向 server 打洞穿透的過程。需要先準備一臺服務器和一臺本地電腦。
UDP打洞源代碼
因為UDP是既可以偵聽又可以發送數據的,所以node.js的代碼實現非常簡單,服務器和本地用一套代碼即可。命名為 onceair.udp.server.js 此文件接收命令行參數,偵聽本地 8090 端口:
var os = require('os') var fs = require('fs') var net = require('net') var dgram = require('dgram') var cp = require('child_process') var path = require('path') var udp = dgram.createSocket('udp4') udp.on('message', function(data, ipdr) { console.log('message') console.log(data.toString()) console.log(ipdr) }) udp.on('error', function(err) { console.log('error') console.log(arguments) }) udp.on('listening', function(err) { console.log('listening') console.log(arguments) }) udp.bind(8090) console.log('udp listening on port 8090') var send = function(message, port, host) { console.log('send') console.log(arguments) udp.send(Buffer.from(message), port || 8090, host || 'anynb.com') } //called directly in command line if (require.main === module) { var port = parseInt(process.argv[2]) var host = process.argv[3] if (port) { send('echo', port, host) } else { send('echo') } }
示例
將 udp.server 上傳到服務器端,然后運行在后臺運行,默認偵聽 8090 端口
/root/node/bin/node onceair.udp.server.js
在客戶端向服務器的 8090 發送消息,同時本地偵聽 8090
$ node onceair.udp.server.js 8090 112.124.126.185
服務器端接收到響應,我們看到這里接收到的客戶端公網IP是180.173.98.126,端口號是 43191,這是路由轉出消息的隨機端口,通過這個端口,就能連接到本地UDP偵聽的8090端口,即是一個臨時的session通道。
message echo { address: '180.173.98.126', family: 'IPv4', port: 43191, size: 4 }
Ctrl + C 中上 onceair.udp.server.js 進程,然后向這個IP和穿透的端口發送數據包,記住操作時間不要太長,否則打通的 session 可能會過期。
/root/node/bin/node onceair.udp.server.js 43191 180.173.98.126 udp listening on port 8090 send { '0': 'echo', '1': 43191, '2': '180.173.98.126' } listening {}
本地接收到的消息,代表通過已經打通
message echo { address: '112.124.126.185', family: 'IPv4', port: 8090, size: 4 }
TCP的內網穿透
實現基于TCP協議的p2p“打洞”過程中,最主要的問題不是來自于TCP協議,而是來自于來自于應用 程序的API接口。這是由于標準的伯克利(Berkeley)套接字的API是圍繞著構建客戶端/服務器程序 而設計的,API允許TCP流套接字通過調用connect()函數來建立向外的連接,或者通過listen()和 accept函數接受來自外部的連接,但是,API不提供類似UDP那樣的,同一個端口既可以向外連接, 又能夠接受來自外部的連接。而且更糟的是,TCP的套接字通常僅允許建立1對1的響應,即應用程 序在將一個套接字綁定到本地的一個端口以后,任何試圖將第二個套接字綁定到該端口的操作都會 失敗。
因此要實現基于TCP的內網穿透,在內網架設一臺HTTP網站,要比UDP復雜得多。
來自:http://ourjs.com/detail/5a4c46fe3506837194998bda