【发布时间】:2011-04-08 20:37:19
【问题描述】:
我有一个简单的 Node.js 程序在我的机器上运行,我想获取运行我的程序的 PC 的本地 IP 地址。如何使用 Node.js 获得它?
【问题讨论】:
-
深思熟虑查看joeyh.name/code/moreutils 和github.com/polotek/procstreams。没有他们,我永远不会离开家。
标签: javascript node.js ip
我有一个简单的 Node.js 程序在我的机器上运行,我想获取运行我的程序的 PC 的本地 IP 地址。如何使用 Node.js 获得它?
【问题讨论】:
标签: javascript node.js ip
您的本地 IP 地址始终为 127.0.0.1。
然后是网络IP地址,您可以从ifconfig (*nix) 或ipconfig (win) 获得。这仅在本地网络中有用。
然后是您的外部/公共 IP 地址,只有当您能够以某种方式向路由器索取该地址时才能获得该地址,或者您可以设置一个外部服务,该服务在收到请求时返回客户端 IP 地址。还存在其他此类服务,例如 whatismyip.com。
在某些情况下(例如,如果您有 WAN 连接)网络 IP 地址和公共 IP 地址相同,并且都可以在外部使用以访问您的计算机。
如果您的网络和公共 IP 地址不同,您可能需要让网络路由器将所有传入连接转发到您的网络 IP 地址。
2013 年更新:
现在有一种新方法可以做到这一点。您可以检查连接的套接字对象是否有一个名为 localAddress 的属性,例如net.socket.localAddress。它返回套接字末端的地址。
最简单的方法是打开一个随机端口并监听它,然后获取你的地址并关闭套接字。
2015 年更新:
以前的已经不行了。
【讨论】:
ifconfig或ipconfig进行系统调用并解析响应字符串?
ifconfig 的输出几乎是唯一的方法。
net.socket 似乎返回了 undefined,因此“执行此操作的新方法”不再起作用。有一个net.Socket,但它没有localAddress 属性。
这是 Node.js 代码的 sn-p 代码,它将解析 ifconfig 的输出并(异步)返回找到的第一个 IP 地址:
(仅在Mac OS X v10.6(Snow Leopard)上进行了测试;我希望它也可以在 Linux 上运行。)
var getNetworkIP = (function () {
var ignoreRE = /^(127\.0\.0\.1|::1|fe80(:1)?::1(%.*)?)$/i;
var exec = require('child_process').exec;
var cached;
var command;
var filterRE;
switch (process.platform) {
// TODO: implement for OSes without the ifconfig command
case 'darwin':
command = 'ifconfig';
filterRE = /\binet\s+([^\s]+)/g;
// filterRE = /\binet6\s+([^\s]+)/g; // IPv6
break;
default:
command = 'ifconfig';
filterRE = /\binet\b[^:]+:\s*([^\s]+)/g;
// filterRE = /\binet6[^:]+:\s*([^\s]+)/g; // IPv6
break;
}
return function (callback, bypassCache) {
// Get cached value
if (cached && !bypassCache) {
callback(null, cached);
return;
}
// System call
exec(command, function (error, stdout, sterr) {
var ips = [];
// Extract IP addresses
var matches = stdout.match(filterRE);
// JavaScript doesn't have any lookbehind regular expressions, so we need a trick
for (var i = 0; i < matches.length; i++) {
ips.push(matches[i].replace(filterRE, '$1'));
}
// Filter BS
for (var i = 0, l = ips.length; i < l; i++) {
if (!ignoreRE.test(ips[i])) {
//if (!error) {
cached = ips[i];
//}
callback(error, ips[i]);
return;
}
}
// Nothing found
callback(error, null);
});
};
})();
使用示例:
getNetworkIP(function (error, ip) {
console.log(ip);
if (error) {
console.log('error:', error);
}
}, false);
如果第二个参数是true,则函数每次都会执行一次系统调用;否则使用缓存的值。
返回所有本地网络地址的数组。
在 Ubuntu 11.04 (Natty Narwhal) 和 Windows XP 32 上测试
var getNetworkIPs = (function () {
var ignoreRE = /^(127\.0\.0\.1|::1|fe80(:1)?::1(%.*)?)$/i;
var exec = require('child_process').exec;
var cached;
var command;
var filterRE;
switch (process.platform) {
case 'win32':
//case 'win64': // TODO: test
command = 'ipconfig';
filterRE = /\bIPv[46][^:\r\n]+:\s*([^\s]+)/g;
break;
case 'darwin':
command = 'ifconfig';
filterRE = /\binet\s+([^\s]+)/g;
// filterRE = /\binet6\s+([^\s]+)/g; // IPv6
break;
default:
command = 'ifconfig';
filterRE = /\binet\b[^:]+:\s*([^\s]+)/g;
// filterRE = /\binet6[^:]+:\s*([^\s]+)/g; // IPv6
break;
}
return function (callback, bypassCache) {
if (cached && !bypassCache) {
callback(null, cached);
return;
}
// System call
exec(command, function (error, stdout, sterr) {
cached = [];
var ip;
var matches = stdout.match(filterRE) || [];
//if (!error) {
for (var i = 0; i < matches.length; i++) {
ip = matches[i].replace(filterRE, '$1')
if (!ignoreRE.test(ip)) {
cached.push(ip);
}
}
//}
callback(error, cached);
});
};
})();
getNetworkIPs(function (error, ip) {
console.log(ip);
if (error) {
console.log('error:', error);
}
}, false);
【讨论】:
filterRE = /\bIP-?[^:\r\n]+:\s*([^\s]+)/g;。除此之外,伟大的剧本,真正的救星。非常感谢!
调用 ifconfig 非常依赖于平台,并且网络层确实知道套接字所在的 IP 地址,所以最好询问它。
Node.js 没有公开执行此操作的直接方法,但您可以打开任何套接字,并询问正在使用的本地 IP 地址。比如打开一个socket到www.google.com:
var net = require('net');
function getNetworkIP(callback) {
var socket = net.createConnection(80, 'www.google.com');
socket.on('connect', function() {
callback(undefined, socket.address().address);
socket.end();
});
socket.on('error', function(e) {
callback(e, 'error');
});
}
用例:
getNetworkIP(function (error, ip) {
console.log(ip);
if (error) {
console.log('error:', error);
}
});
【讨论】:
此信息可以在os.networkInterfaces() 中找到——一个将网络接口名称映射到其属性的对象(例如,一个接口可以有多个地址):
'use strict';
const { networkInterfaces } = require('os');
const nets = networkInterfaces();
const results = Object.create(null); // Or just '{}', an empty object
for (const name of Object.keys(nets)) {
for (const net of nets[name]) {
// Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses
if (net.family === 'IPv4' && !net.internal) {
if (!results[name]) {
results[name] = [];
}
results[name].push(net.address);
}
}
}
// 'results'
{
"en0": [
"192.168.1.101"
],
"eth0": [
"10.0.0.101"
],
"<network name>": [
"<ip>",
"<ip alias>",
"<ip alias>",
...
]
}
// results["en0"][0]
"192.168.1.101"
【讨论】:
Object.values(require('os').networkInterfaces()).reduce((r, list) => r.concat(list.reduce((rr, i) => rr.concat(i.family==='IPv4' && !i.internal && i.address || []), [])), [])
我正在使用 Node.js 0.6.5:
$ node -v
v0.6.5
这是我的工作:
var util = require('util');
var exec = require('child_process').exec;
function puts(error, stdout, stderr) {
util.puts(stdout);
}
exec("hostname -i", puts);
【讨论】:
hostname -I(大写i)。它返回机器的所有已分配 IP 地址的列表。第一个 IP 地址是您需要的。该 IP 是连接到当前已启动接口的 IP。
运行程序来解析结果似乎有点不确定。这是我使用的。
require('dns').lookup(require('os').hostname(), function (err, add, fam) {
console.log('addr: ' + add);
})
这应该返回您的第一个网络接口本地 IP 地址。
【讨论】:
这是我获取本地 IP 地址的实用方法,假设您正在寻找 IPv4 地址并且机器只有一个真实的网络接口。它可以很容易地重构为返回多接口机器的 IP 地址数组。
function getIPAddress() {
var interfaces = require('os').networkInterfaces();
for (var devName in interfaces) {
var iface = interfaces[devName];
for (var i = 0; i < iface.length; i++) {
var alias = iface[i];
if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal)
return alias.address;
}
}
return '0.0.0.0';
}
【讨论】:
getLocalIP = (interfaceName = "en0",version = "IPv4")-> iface = require('os').networkInterfaces()[interfaceName] for alias in iface if (alias.family == version && !alias.internal) return alias.address return "0.0.0.0"
您可以使用 os 模块找到您机器的任何 IP 地址 - 这是 Node.js 的 本机:
var os = require('os');
var networkInterfaces = os.networkInterfaces();
console.log(networkInterfaces);
您只需致电 os.networkInterfaces(),您将获得一个易于管理的列表 - 比按联赛运行 ifconfig 更容易。
【讨论】:
var address = networkInterfaces['venet0:0'][0].address
os.networkInterfaces() 返回一个简单的 JSON 对象以使用 ;)
对于任何对简洁感兴趣的人,这里有一些不需要插件/依赖项的“单行”,这些插件/依赖项不是标准 Node.js 安装的一部分:
eth0 的公共 IPv4 和 IPv6 地址作为数组:
var ips = require('os').networkInterfaces().eth0.map(function(interface) {
return interface.address;
});
eth0(通常是 IPv4)的第一个公共 IP 地址为字符串:
var ip = require('os').networkInterfaces().eth0[0].address;
【讨论】:
en0 和 en1 用于以太网和 wifi。在 Windows 上,我有 Local Area Connection 和 Wireless Network Connection。
这是jhurliman's answer的多IP地址版本:
function getIPAddresses() {
var ipAddresses = [];
var interfaces = require('os').networkInterfaces();
for (var devName in interfaces) {
var iface = interfaces[devName];
for (var i = 0; i < iface.length; i++) {
var alias = iface[i];
if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
ipAddresses.push(alias.address);
}
}
}
return ipAddresses;
}
【讨论】:
https://github.com/indutny/node-ip
var ip = require("ip");
console.dir ( ip.address() );
【讨论】:
这是一个允许您获取本地 IP 地址的变体(在 Mac 和 Windows 上测试):
var
// Local IP address that we're trying to calculate
address
// Provides a few basic operating-system related utility functions (built-in)
,os = require('os')
// Network interfaces
,ifaces = os.networkInterfaces();
// Iterate over interfaces ...
for (var dev in ifaces) {
// ... and find the one that matches the criteria
var iface = ifaces[dev].filter(function(details) {
return details.family === 'IPv4' && details.internal === false;
});
if(iface.length > 0)
address = iface[0].address;
}
// Print the result
console.log(address); // 10.25.10.147
【讨论】:
Google 在搜索“Node.js 获取服务器 IP”时将我引导至此问题,所以让我们为那些试图在他们的 Node.js 中实现此目标的人提供一个替代答案服务器程序(可能是原发帖人的情况)。
在服务器只绑定一个IP地址的最简单的情况下,应该不需要确定IP地址,因为我们已经知道我们将它绑定到哪个地址(例如,传递给@的第二个参数987654323@函数)。
在服务器绑定到多个 IP 地址的不太简单的情况下,我们可能需要确定客户端连接的接口的 IP 地址。正如 Tor Valamo 简要建议的那样,如今,我们可以轻松地从连接的套接字及其localAddress 属性中获取此信息。
例如,如果程序是网络服务器:
var http = require("http")
http.createServer(function (req, res) {
console.log(req.socket.localAddress)
res.end(req.socket.localAddress)
}).listen(8000)
如果是通用 TCP 服务器:
var net = require("net")
net.createServer(function (socket) {
console.log(socket.localAddress)
socket.end(socket.localAddress)
}).listen(8000)
在运行服务器程序时,该解决方案提供了非常高的可移植性、准确性和效率。
更多详情见:
【讨论】:
对最佳答案的改进,原因如下:
代码应尽可能不言自明。
应避免使用 for...in... 枚举数组。
for...in... 枚举应该被验证以确保被枚举的对象包含您正在寻找的属性。由于 JavaScript 是松散类型的,并且 for...in... 可以交给任意对象来处理;验证我们要查找的属性是否可用会更安全。
var os = require('os'),
interfaces = os.networkInterfaces(),
address,
addresses = [],
i,
l,
interfaceId,
interfaceArray;
for (interfaceId in interfaces) {
if (interfaces.hasOwnProperty(interfaceId)) {
interfaceArray = interfaces[interfaceId];
l = interfaceArray.length;
for (i = 0; i < l; i += 1) {
address = interfaceArray[i];
if (address.family === 'IPv4' && !address.internal) {
addresses.push(address.address);
}
}
}
}
console.log(addresses);
【讨论】:
根据评论,以下是当前版本的 Node.js 的工作原理:
var os = require('os');
var _ = require('lodash');
var ip = _.chain(os.networkInterfaces())
.values()
.flatten()
.filter(function(val) {
return (val.family == 'IPv4' && val.internal == false)
})
.pluck('address')
.first()
.value();
对上述答案之一的评论缺少对values() 的调用。看起来 os.networkInterfaces() 现在返回一个对象而不是数组。
【讨论】:
_(...),.filter(..) 可以改写为.where({family: 'IPv4', internal: false}),你可以去掉最后的value(),因为.first() 在链接时会为你做。跨度>
这是前面示例的变体。它会小心过滤掉VMware 接口等。如果您不传递索引,它会返回所有地址。否则,您可能希望将其设置为默认值 0,然后只传递 null 以获取所有内容,但您会对其进行排序。如果愿意添加,您还可以为正则表达式过滤器传递另一个参数。
function getAddress(idx) {
var addresses = [],
interfaces = os.networkInterfaces(),
name, ifaces, iface;
for (name in interfaces) {
if(interfaces.hasOwnProperty(name)){
ifaces = interfaces[name];
if(!/(loopback|vmware|internal)/gi.test(name)){
for (var i = 0; i < ifaces.length; i++) {
iface = ifaces[i];
if (iface.family === 'IPv4' && !iface.internal && iface.address !== '127.0.0.1') {
addresses.push(iface.address);
}
}
}
}
}
// If an index is passed only return it.
if(idx >= 0)
return addresses[idx];
return addresses;
}
【讨论】:
用途:
var os = require('os');
var networkInterfaces = os.networkInterfaces();
var arr = networkInterfaces['Local Area Connection 3']
var ip = arr[1].address;
【讨论】:
这是我的变体,它允许以可移植方式获取 IPv4 和 IPv6 地址:
/**
* Collects information about the local IPv4/IPv6 addresses of
* every network interface on the local computer.
* Returns an object with the network interface name as the first-level key and
* "IPv4" or "IPv6" as the second-level key.
* For example you can use getLocalIPs().eth0.IPv6 to get the IPv6 address
* (as string) of eth0
*/
getLocalIPs = function () {
var addrInfo, ifaceDetails, _len;
var localIPInfo = {};
//Get the network interfaces
var networkInterfaces = require('os').networkInterfaces();
//Iterate over the network interfaces
for (var ifaceName in networkInterfaces) {
ifaceDetails = networkInterfaces[ifaceName];
//Iterate over all interface details
for (var _i = 0, _len = ifaceDetails.length; _i < _len; _i++) {
addrInfo = ifaceDetails[_i];
if (addrInfo.family === 'IPv4') {
//Extract the IPv4 address
if (!localIPInfo[ifaceName]) {
localIPInfo[ifaceName] = {};
}
localIPInfo[ifaceName].IPv4 = addrInfo.address;
} else if (addrInfo.family === 'IPv6') {
//Extract the IPv6 address
if (!localIPInfo[ifaceName]) {
localIPInfo[ifaceName] = {};
}
localIPInfo[ifaceName].IPv6 = addrInfo.address;
}
}
}
return localIPInfo;
};
这是同一函数的 CoffeeScript 版本:
getLocalIPs = () =>
###
Collects information about the local IPv4/IPv6 addresses of
every network interface on the local computer.
Returns an object with the network interface name as the first-level key and
"IPv4" or "IPv6" as the second-level key.
For example you can use getLocalIPs().eth0.IPv6 to get the IPv6 address
(as string) of eth0
###
networkInterfaces = require('os').networkInterfaces();
localIPInfo = {}
for ifaceName, ifaceDetails of networkInterfaces
for addrInfo in ifaceDetails
if addrInfo.family=='IPv4'
if !localIPInfo[ifaceName]
localIPInfo[ifaceName] = {}
localIPInfo[ifaceName].IPv4 = addrInfo.address
else if addrInfo.family=='IPv6'
if !localIPInfo[ifaceName]
localIPInfo[ifaceName] = {}
localIPInfo[ifaceName].IPv6 = addrInfo.address
return localIPInfo
console.log(getLocalIPs()) 的示例输出
{ lo: { IPv4: '127.0.0.1', IPv6: '::1' },
wlan0: { IPv4: '192.168.178.21', IPv6: 'fe80::aa1a:2eee:feba:1c39' },
tap0: { IPv4: '10.1.1.7', IPv6: 'fe80::ddf1:a9a1:1242:bc9b' } }
【讨论】:
Underscore.js 和 Lodash 的正确单行代码是:
var ip = require('underscore')
.chain(require('os').networkInterfaces())
.values()
.flatten()
.find({family: 'IPv4', internal: false})
.value()
.address;
【讨论】:
.find({family: 'IPv4', internal: false}) 以及更短更优雅的代码
如果您想了解整个简洁,这里使用Lodash:
var os = require('os');
var _ = require('lodash');
var firstLocalIp = _(os.networkInterfaces()).values().flatten().where({ family: 'IPv4', internal: false }).pluck('address').first();
console.log('First local IPv4 address is ' + firstLocalIp);
【讨论】:
这是一个简单的原生 JavaScript 版本,用于获取单个 IP 地址:
function getServerIp() {
var os = require('os');
var ifaces = os.networkInterfaces();
var values = Object.keys(ifaces).map(function(name) {
return ifaces[name];
});
values = [].concat.apply([], values).filter(function(val){
return val.family == 'IPv4' && val.internal == false;
});
return values.length ? values[0].address : '0.0.0.0';
}
【讨论】:
对于 Linux 和 macOS 的使用,如果你想通过同步的方式获取你的 IP 地址,试试这个:
var ips = require('child_process').execSync("ifconfig | grep inet | grep -v inet6 | awk '{gsub(/addr:/,\"\");print $2}'").toString().trim().split("\n");
console.log(ips);
结果会是这样的:
['192.168.3.2', '192.168.2.1']
【讨论】:
更大的问题是“为什么?”
如果您需要知道您的 Node.js 实例正在侦听的服务器,您可以使用req.hostname。
【讨论】:
接受的答案是异步的。我想要一个同步版本:
var os = require('os');
var ifaces = os.networkInterfaces();
console.log(JSON.stringify(ifaces, null, 4));
for (var iface in ifaces) {
var iface = ifaces[iface];
for (var alias in iface) {
var alias = iface[alias];
console.log(JSON.stringify(alias, null, 4));
if ('IPv4' !== alias.family || alias.internal !== false) {
debug("skip over internal (i.e. 127.0.0.1) and non-IPv4 addresses");
continue;
}
console.log("Found IP address: " + alias.address);
return alias.address;
}
}
return false;
【讨论】:
forEach 是同步的。
与其他答案类似,但更简洁:
'use strict';
const interfaces = require('os').networkInterfaces();
const addresses = Object.keys(interfaces)
.reduce((results, name) => results.concat(interfaces[name]), [])
.filter((iface) => iface.family === 'IPv4' && !iface.internal)
.map((iface) => iface.address);
【讨论】:
Object.keys(interfaces).reduce(...) 替换为Object.values(interfaces).flat(),这将是一回事。
使用 npm ip 模块:
var ip = require('ip');
console.log(ip.address());
> '192.168.0.117'
【讨论】:
我写了一个Node.js module,它通过查看哪个网络接口包含您的默认网关来确定您的本地 IP 地址。
这比从os.networkInterfaces() 中选择接口或主机名的 DNS 查找更可靠。它能够忽略 VMware 虚拟接口、环回和 VPN 接口,并且可以在 Windows、Linux、Mac OS 和 FreeBSD 上运行。在后台,它执行route.exe 或netstat 并解析输出。
var localIpV4Address = require("local-ipv4-address");
localIpV4Address().then(function(ipAddress){
console.log("My IP address is " + ipAddress);
// My IP address is 10.4.4.137
});
【讨论】:
在 macOS 上开发应用程序时,您想在手机上进行测试,并且需要您的应用程序自动选择 localhost IP 地址。
require('os').networkInterfaces().en0.find(elm => elm.family=='IPv4').address
这里只是提到如何自动找到IP地址。 要对此进行测试,您可以转到终端命中
node
os.networkInterfaces().en0.find(elm => elm.family=='IPv4').address
输出将是您的本地 IP 地址。
【讨论】:
安装一个名为 ip 的模块,例如:
npm install ip
然后使用这个代码:
var ip = require("ip");
console.log(ip.address());
【讨论】:
<socket>.localPort 和 <socket.remotePort 用于 tcp 连接。 nodejs.org/api/net.html#net_class_net_socket
DockerNAT IP
这里有一个简洁的小单线,它可以在功能上做到这一点:
const ni = require('os').networkInterfaces();
Object
.keys(ni)
.map(interf =>
ni[interf].map(o => !o.internal && o.family === 'IPv4' && o.address))
.reduce((a, b) => a.concat(b))
.filter(o => o)
[0];
【讨论】:
reduce 的调用,并将对map 的调用替换为对flatMap 的调用。