Q Q 群 : 一起学前端
Javascript/node如何获取本机IP
[TOC]
为什么要获取本机IP
- 以前做的一个Electron的客户端启动Server需要把本机IP显示出来
- 一个基于RK3399的硬件平台的APP进行串口通信另一方需要进行IP校验
如何获取
我们知道JS是客户端语言,单纯的JS是无法获取本机IP的,即使有navigator也只能获取网络的连接类型和监听网络的变化,而无法得知IP信息
window.navagator.connection;
{
downlink: 2.95
downlinkMax: Infinity
effectiveType: "4g"
onchange: null
ontypechange: null
rtt: 50
saveData: false
type: "wifi"
}
虽然BOM的API无法获取我们可以采取其他方式
JS获取本机IP
- 通过接口让Server端告知我们的client ip
- 通过WebRTC来获取本机IP
JS通过接口获取
我们可以发送一个Request,在Server端就可以得知我们的IP,连接外网的情况外网Server得知的就是外网IP,只有内网的情况下Server得知的就是我们的内网IP,总之一句话通过接口获取的IP都是相对IP
const express = require("express");
const app = express();
app.set('trust proxy', true);
app.get("/api/get_pubip", (req, res) => {
const { ip } = req;
res.send({code: 0, data: {ip}, msg: "success"});
})
app.listen(3002);
- 经过测试在没有经过代理的情况下本机localhost访问返回数据为
// http://localhost:3002/api/get_pubip
{
"code": 0,
"data": {"ip": "::1"},
"msg": "success"
}
- 经过nginx代理本机访问的返回数据
// http://localhost:8080/api/get_pubip
{
"code": 0,
"data": {"ip": "::ffff:127.0.0.1"},
"msg": "success"
}
- 其他机器(192.168.0.110)访问返回数据
// http://l192.168.0.108/api/get_pubip
{
"code": 0,
"data": {"ip": "::ffff:192.168.0.110"},
"msg": "success"
}
WebRTC获取本机IP
WebRTC进行音视频通话时是需要进行媒体协商和网络协商的,在网络协商的过程中就需要知道双方的内外网IP地址,网络协商是需要借助IceServer的帮助的,协商通过后就可以进行后续的UPD通信进行音视频数据的packet发送
function getIPs(callback){
var ip_dups = {};
var RTCPeerConnection = window.RTCPeerConnection
|| window.mozRTCPeerConnection
|| window.webkitRTCPeerConnection;
var useWebKit = !!window.webkitRTCPeerConnection;
var mediaConstraints = {
optional: [{RtpDataChannels: true}]
};
// 这里就是需要的ICEServer了
var servers = {
iceServers: [
{urls: "stun:stun.services.mozilla.com"},
{urls: "stun:stun.l.google.com:19302"},
]
};
var pc = new RTCPeerConnection(servers, mediaConstraints);
function handleCandidate(candidate){
var ip_regex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/
var hasIp = ip_regex.exec(candidate)
if (hasIp) {
var ip_addr = ip_regex.exec(candidate)[1];
if(ip_dups[ip_addr] === undefined)
callback(ip_addr);
ip_dups[ip_addr] = true;
}
}
// 网络协商的过程
pc.onicecandidate = function(ice){
if(ice.candidate) {
handleCandidate(ice.candidate.candidate);
}
};
pc.createDataChannel("");
//创建一个SDP(session description protocol)会话描述协议 是一个纯文本信息 包含了媒体和网络协商的信息
pc.createOffer(function(result){
pc.setLocalDescription(result, function(){}, function(){});
}, function(){});
setTimeout(function(){
var lines = pc.localDescription.sdp.split('\n');
lines.forEach(function(line){
if(line.indexOf('a=candidate:') === 0)
handleCandidate(line);
});
}, 1000);
}
getIPs(function(ip){console.log(ip);});
Webrtc得到的IP结果和开源API获取的结果对比
// WebRTC获取的结果 122.4.121.156
// 开源API获取到的IP地址
{
"ip": "122.4.121.156",
"city": 1569,
"region": "中国|0|山东省|青岛市|电信"
}
其实Webrtc在媒体协商时获取的IP不止一个,总共有四种类型host
srflx
prflx
relay
candidate四种类型说明
候选类型 | code | 来源 | 传输 | 用途 | 主机候选项 | host | 网卡 | 信令服务 | 从网卡中获取本地传输地址 | 服务器反射候选项 | srflx | STUN | 信令服务 | 从发给stun服务的stun检查中获取到的传输地址 | 对象反射候选项 | prflx | ICE代理 | STUN Binding | 从对方ice代理发送stun连接检查中获取的传输地址 | 中继候选者 | relay | TURN | 信令服务器 | 媒体中继服务器的传输地址 | #### 你会发现Webrtc是无法获取到本机IP | host获取的一直是xxxxx.local的东东为什么呢? | 请参考文末的mdns 文档 | ### 接下来看看用node如何获取本机ip |
---|
-
- 通过os模块来获取
-
- 通过广播来获取
OS模块获取本机IP
let netDict = os.networkInterfaces();
for (const devName in netDict) {
let netList = netDict[devName];
for (var i = 0; i < netList.length; i++) {
let { address, family, internal,mac } = netList[i],
isvm = isVmNetwork(mac);
if (family === 'IPv4' && address !== '127.0.0.1' && !internal) {
return address;
}
}
}
以上方法确实获取本机IP 但是假如你本机装了一个虚拟机获取的ip可能就是你虚拟机的IP了 或者你通过VPN访问网络获取到的有可能是你的VPN分配的IP,所以我们需要根据MAC地址来判断是否是虚拟机/VPN
// 增加一个判断VM虚拟机的方法
// 在上面方法的if中加上这个方法的返回判断就行了
function isVmNetwork (mac) {
// 常见的虚拟网卡MAC地址和厂商
let vmNetwork = [
"00:05:69", //vmware1
"00:0C:29", //vmware2
"00:50:56", //vmware3
"00:1C:42", //parallels1
"00:03:FF", //microsoft virtual pc
"00:0F:4B", //virtual iron 4
"00:16:3E", //red hat xen , oracle vm , xen source, novell xen
"08:00:27", //virtualbox
"00:00:00", // VPN
]
for (let i = 0; i < vmNetwork.length; i++) {
let mac_per = vmNetwork[i];
if (mac.startsWith(mac_per)) {
return true
}
}
return false;
}
广播获取本机IP
开启一个广播服务端监听message并发送广播,就可以接受到本机发送的广播,从而获取到发送端(本机)的address信息
const dgram = require("dgram");
const socket = dgram.createSocket("udp4");
const getLocalIp = () => {
return new Promise((resolve, reject) => {
socket.on("error", err => {
reject(err);
socket.close();
})
socket.on("message", (msg, rinfo) => {
let { address, port } = rinfo;
resolve(address);
})
socket.bind(19319, _=> {
socket.setBroadcast(true);
});
var message = new Buffer.from("hello");
socket.send(message, 0, message.length, 19319, "255.255.255.255", (err, bytes)=> {
if (err) {
reject(err);
return
}
})
})
}
getLocalIp().then(res => {
console.log(res);
// 192.168.0.108 这里打印的结果和ifconf得到的结果一致
})
你还知道哪些获取IP的方法欢迎留言或进群讨论
参考文档
CSDN
WebRTC cancidate文档
关于虚拟机MAC
mdns
mdns
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!