Javascript 存储为 int 的 IP 地址会导致溢出吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8105629/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
IP-addresses stored as int results in overflow?
提问by JPuge
I'm writing a chat-server in node.js, and I want to store connected users IP-addresses in a mysql database as (unsigned) integers. I have written a javascript method to convert an ip-address as string to an integer. I get some strange results however.
我正在 node.js 中编写一个聊天服务器,我想将连接的用户 IP 地址作为(无符号)整数存储在 mysql 数据库中。我编写了一个 javascript 方法来将 ip 地址作为字符串转换为整数。然而,我得到了一些奇怪的结果。
Here is my code:
这是我的代码:
function ipToInt(ip) {
var parts = ip.split(".");
var res = 0;
res += parseInt(parts[0], 10) << 24;
res += parseInt(parts[1], 10) << 16;
res += parseInt(parts[2], 10) << 8;
res += parseInt(parts[3], 10);
return res;
}
When I run call the method as ipToInt("192.168.2.44");
the result I get is -1062731220
.
It seems like an overflow has occurred, which is strange, because the expected output (3232236076)
is inside the number range in javascript (2^52).
当我运行调用该方法时,ipToInt("192.168.2.44");
我得到的结果是-1062731220
. 似乎发生了溢出,这很奇怪,因为预期输出(3232236076)
在 javascript (2^52) 中的数字范围内。
When I inspect -1062731220
in binary form, I can see the 3232236076
is preserved, but filled with leading 1's.
当我-1062731220
以二进制形式检查时,我可以看到3232236076
保留了,但填充了前导 1。
I'm not sure, but I think the problem is with signed vs. unsigned integers.
我不确定,但我认为问题在于有符号整数与无符号整数。
Can any of you explain what is going on?
And possibly how to parse -1062731220
back to an string ip?
你们中的任何人都可以解释发生了什么吗?以及可能如何解析-1062731220
回字符串 ip?
回答by evan
Why is the converted IP negative?
为什么转换后的IP是负数?
It's NOT an overflow. The first part of your IP address is 192 which converts to 11000000 in binary. You then shift that all the way to the left. When there is a 1 in the leftmost position of a 32 bit number, it's negative.
这不是溢出。IP 地址的第一部分是 192,它转换为二进制的 11000000。然后将其一直向左移动。当 32 位数字的最左边有一个 1 时,它是负数。
How do you convert back to a string?
你如何转换回字符串?
Do the same thing you did to convert from a string but in reverse. Shift right (and mask)!
做与从字符串转换相同的事情,但相反。右移(和掩码)!
function intToIP(int) {
var part1 = int & 255;
var part2 = ((int >> 8) & 255);
var part3 = ((int >> 16) & 255);
var part4 = ((int >> 24) & 255);
return part4 + "." + part3 + "." + part2 + "." + part1;
}
Why reinvent the wheel? From Google:
为什么要重新发明轮子?来自谷歌:
OR, you can use what I found here:
http://javascript.about.com/library/blipconvert.htm
或者,您可以使用我在这里找到的内容:http:
//javascript.about.com/library/blipconvert.htm
function dot2num(dot)
{
var d = dot.split('.');
return ((((((+d[0])*256)+(+d[1]))*256)+(+d[2]))*256)+(+d[3]);
}
function num2dot(num)
{
var d = num%256;
for (var i = 3; i > 0; i--)
{
num = Math.floor(num/256);
d = num%256 + '.' + d;
}
return d;
}
回答by Pointy
The result of the "<<" operator is always a signed, 32-bit integer, as per the spec.
根据规范,“<<”运算符的结果始终是有符号的 32 位整数。
When you shift back, use ">>>" to do an unsigned right shift.
向后移动时,使用“>>>”进行无符号右移。
回答by Guy
You might also find this pattern useful:
您可能还会发现此模式很有用:
ip.toLong = function toInt(ip){
var ipl=0;
ip.split('.').forEach(function( octet ) {
ipl<<=8;
ipl+=parseInt(octet);
});
return(ipl >>>0);
};
ip.fromLong = function fromInt(ipl){
return ( (ipl>>>24) +'.' +
(ipl>>16 & 255) +'.' +
(ipl>>8 & 255) +'.' +
(ipl & 255) );
};
If you're using something like node.js where you can add functionality through something like Npm then you can simply do:
如果你使用像 node.js 这样的东西,你可以通过像 Npm 这样的东西添加功能,那么你可以简单地做:
npm install ip
To get that functionality from the source which is here:
https://github.com/indutny/node-ip/blob/master/lib/ip.js
要从这里的源获取该功能:https:
//github.com/indutny/node-ip/blob/master/lib/ip.js
You will also get a bunch of other IP utility functions with that.
您还将获得许多其他 IP 实用程序功能。
回答by Mike
You shifted left to get the original number - which is just 4 sets of bits regardless of the sign.
您向左移动以获得原始数字 - 无论符号如何,它都只有 4 组位。
Shift right to get back to the IP. Doesn't matter what the sign is.
右移返回 IP。标志是什么并不重要。
回答by tsypa
const ip2int = (x) => (x.split('.').reduce((a, v) => ((a << 8) + (+v)), 0) >>> 0);
回答by Shl
One-Liner:
单线:
const ipToLong = ip => ip.split('.').map(parseFloat).reduce((total, part) => total * 256 + part);
回答by FlyingGuy
IP Addresses in the V4 space are unsigned 32 bit numbers, hence the IP address of FF.FF.FF.FF is 2^32 and cannot be greater then that number. Please see:
V4 空间中的 IP 地址是无符号的 32 位数字,因此 FF.FF.FF.FF 的 IP 地址是 2^32 并且不能大于该数字。请参见:
This stack overflow article on the same subject
To turn that number back into an IP address you must break the number down into its 4 parts since each byte is one octet of the address so convert the number to hex and then parse out each pair. You may or may not have to add a leading zero for the first octet.
要将该数字重新转换为 IP 地址,您必须将该数字分解为 4 部分,因为每个字节是地址的一个八位字节,因此将数字转换为十六进制,然后解析出每一对。您可能需要也可能不需要为第一个八位字节添加前导零。
Additionally you mayhave to deal with byte order of the integer ( endien issues ) but since most systems are intel based these days you might not have to deal with that.
此外,您可能必须处理整数的字节顺序(endien 问题),但由于现在大多数系统都是基于英特尔的,因此您可能不必处理它。
回答by user2321638
var aaa = Number("0b"+ "192.168.2.44".split(".").map(
function(dec){
return ("00000000" + Number(dec).toString(2)).slice(-8);
}).join(""));
aaa.toString(2).match(/.{1,8}/g).map(
function(bin){
return Number("0b"+bin);
}).join(".");
回答by George Crowson
I revised Evan's final answer a bit, particularly dot2num. It functions the same but might be more readable and is marginally slower.
我稍微修改了 Evan 的最终答案,尤其是 dot2num。它的功能相同,但可能更具可读性并且速度稍慢。
function ip2num(ip) {
var parts = ip.split('.');
var num = 0;
num += d[0] * Math.pow(2, 24);
num += d[1] * Math.pow(2, 16);
num += d[2] * Math.pow(2, 8);
num += d[3];
return num;
}
function num2ip(num) {
var ip = num % 256;
for (var i=3; i > 0; i--) {
num = Math.floor(num / 256);
ip = num % 256 + '.' + ip;
}
return ip;
}
回答by TCK
Try this solution, it might help:
试试这个解决方案,它可能会有所帮助:
function IpToInteger(ipAddr)
{
var parts = ipAddr.split('.');
return (((parts[0] ? parts[0] << 24 : 0) |
(parts[1] ? parts[1] << 16 : 0) |
(parts[2] ? parts[2] << 8 : 0) |
(parts[3])) >>> 0);
}