最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • JS/node获取本机ip的方法

    正文概述 掘金(wangfpp)   2021-06-13   886

    Q Q 群 : 一起学前端
    Javascript/node如何获取本机IP

    [TOC]

    为什么要获取本机IP

    1. 以前做的一个Electron的客户端启动Server需要把本机IP显示出来
    2. 一个基于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

    1. 通过接口让Server端告知我们的client ip
    2. 通过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网卡信令服务从网卡中获取本地传输地址服务器反射候选项srflxSTUN信令服务从发给stun服务的stun检查中获取到的传输地址对象反射候选项prflxICE代理STUN Binding从对方ice代理发送stun连接检查中获取的传输地址中继候选者relayTURN信令服务器媒体中继服务器的传输地址#### 你会发现Webrtc是无法获取到本机IPhost获取的一直是xxxxx.local的东东为什么呢?请参考文末的mdns文档### 接下来看看用node如何获取本机ip
      1. 通过os模块来获取
      1. 通过广播来获取

    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


    起源地下载网 » JS/node获取本机ip的方法

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元