Node.JS中UDP打洞穿透內網路由,架設內網服務器技術詳解及源碼

CliParamor 6年前發布 | 28K 次閱讀 UDP Node.js Node.js 開發

在制作一款私有云網絡存儲產品時,很多客戶反應,他們希望能遠程訪問。遠程訪問內網服務器成本最低的方式應該就是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

 

 本文由用戶 CliParamor 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!