2017-04-03 67 views
4

我正在构建一个函数,它将一个无符号的int32转换为一个ipv4地址,并且它一切正常,直到我测试范围的上半部分。cffunction/cfargument pass unsigned int32

<cffunction name="Int32ToIPv4" returntype="string" output="false" access="public" hint="returns IPv4 address for int32 number"> 
    <cfargument name="nInt32" type="numeric" required="yes" hint="int32 to convert to ipv4 address"> 

    <cfreturn 
     bitAnd((arguments.nInt32/16777216), 255) & "." 
     & bitAnd((arguments.nInt32/65536), 255) & "." 
     & bitAnd((arguments.nInt32/256), 255) & "." 
     & bitAnd(arguments.nInt32, 255) 
    > 
</cffunction> 

的ColdFusion似乎解释类型= “数字” 是一个签署 32位整数。

这个例子的工作原理:

Int32ToIPv4(nInt32 = 1181772947) = #Int32ToIPv4(nInt32 = 1181772947)# (expected value = 70.112.108.147)<br> 

这个例子将失败:

Int32ToIPv4(nInt32 = 3401190660) = #Int32ToIPv4(nInt32 = 3401190660)# (expected value = 202.186.13.4)<br> 

的错误信息是:“不能将值3.40119066E9转换为整数,因为它不适合一个整数里面。”

我必须将此数字作为字符串传递并在使用它之前将其转换为Java无符号整数?

我想在ipv6地址(无符号的128位整数)上做点类似的事情。任何建议这种类型的数据类型将不胜感激。

回答

3

它实际上是bitAnd()施加32位整数限制,而不是cfargument。有趣的是,如果你单独检查每个计算,前三(3)工作正常。由于这种划分,传入bitAnd()的值实际上足够小以适应INT的内部。然而,最后一个使用显然太大的原始值,并且这是造成这个具体数字的错误的原因。

bitAnd( (3401190660/16777216), 255) // Actual => 202.7267611032, 255 
bitAnd( (3401190660/65536), 255) // Actual => 51898.05084233, 255 
bitAnd( (3401190660/256), 255) // Actual =>13285901.0156, 255 
bitAnd(3401190660, 255) // Too big! 

由于大多数的CF相关的数学函数被限制为32个整数,我不知道是否(或如何简单),它可以用CF单独完成。假设你使用Java 8+,你也可以访问新的未签名方法,如Integer.parseUnsignedInt(String)

我个人认为这将是一个很好的学习练习。但是,除非您非常熟悉签名与未签名的细节以及它与IP4和IP6地址的关系,否则您可能只想使用现有的Java库来避免常见的缺陷。如Guava's InetAdress

// IP4 
input = 3401190660; 
uint = createObject("java", "java.lang.Integer").parseUnsignedInt(input); 
inet = createObject("Java", "com.google.common.net.InetAddresses"); 
result = inet.fromInteger(uint).getHostAddress(); 
+0

感谢您的解释@leigh。我确实想出了一个纯Java本地解决方案,我将发布评论/信息,但我会将您的答案标记为答案。 –

+0

@Scott - 嘿......我想我们在SO上看到了相同的线索。在我的咖啡开始前,我给了它一个快速(不成功)的旋转,但肯定错过了一些东西。很高兴你知道了:-) – Leigh

2

我没有拿出,参与传递的32位无符号INT本地Java的解决方案。所以,@Leigh对于cfargument正常工作是正确的。

<cffunction name="UInt32ToIPv4" returntype="string" output="no" access="public" hint="returns IPv4 address for uint32 number"> 
    <cfargument name="nUInt32" type="numeric" required="yes" hint="uint32 to convert to ipv4 address"> 

    <cfset local['JavaLangInteger'] = CreateObject("java", "java.lang.Integer")> 
    <cfset local['JavaMathBigInteger'] = CreateObject("java", "java.math.BigInteger")> 
    <cfset local['JavaNetInetAddress'] = CreateObject("java", "java.net.InetAddress")> 

    <cfif arguments.nUInt32 EQ 0> 
     <cfreturn ""> 
    </cfif> 

    <cftry> 
     <cfset local['vcIPv4'] = local.JavaNetInetAddress.getByAddress(local.JavaMathBigInteger.valueOf(local.JavaLangInteger.parseUnsignedInt(arguments.nUInt32)).toByteArray())> 
     <cfreturn reReplace(local.vcIPv4, "[^0-9\.]", "", "all")> 
     <cfcatch type="any"> 
      <cfreturn ""> 
     </cfcatch> 
    </cftry> 
</cffunction> 

让我知道,如果有此解决方案的任何问题,我想我会用它来代替公共Java库。

我已经编写了ipv6的函数来处理转换(无符号128位int到/从ipv6)。不确定这些功能是否有兴趣。如果有,我会用该代码创建单独的问题/答案。

+0

不错!你有没有使用类似的ip6的东西? (小方面说明,只需使用'local.vcIPv4.ge​​tHostAddress()'返回地址而不是在对象上使用'reReplace()')。 – Leigh

+0

@李,谢谢。由于存在若干差异,我不会称之为类似的。 128位无符号它的底层ipv6号码,我用java.net.Inet6Address和java.math.BigInteger,但该库有两个问题。如果数量太小,就会失败。太大,再次签署问题。 –

+0

@Leigh,关于reReplace(),我第一次尝试返回字符串将包含一个前导“/”。我会再次检查代码,看看是否仍然如此,并让你知道。 –