2017-04-03 64 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(),我第一次嘗試返回字符串將包含一個前導「/」。我會再次檢查代碼,看看是否仍然如此,並讓你知道。 –