'參考文檔:http://lumaqq.linuxsir.org/article/qqwry_format_detail.html
'作者: gounliey
'Email:4473117@qq.com
'第一次寫(xiě)東西出來(lái)大家分享,還有很多不足之處,請(qǐng)大家指點(diǎn)。
'輔助類,用于保存IP索引信息
Public Class CZ_INDEX_INFO
Public IpSet As UInt32
,ublic IpEnd As UInt32
,ublic Offset As UInt32
Sub New()
,,,pSet = 0
,,,pEnd = 0
,,,ffset = 0
,nd Sub
End Class
'讀取純真IP數(shù)據(jù)庫(kù)類
Public Class PHCZIP
Protected bFilePathInitialized As Boolean
,rotected FilePath As String
Protected FileStrm As FileStream
,rotected Index_Set As UInt32
Protected Index_End As UInt32
,rotected Index_Count As UInt32
,rotected Search_Index_Set As UInt32
Protected Search_Index_End As UInt32
,rotected Search_Set As CZ_INDEX_INFO
,rotected Search_Mid As CZ_INDEX_INFO
Protected Search_End As CZ_INDEX_INFO
,ublic Sub New()
,FilePathInitialized = False
End Sub
,ublic Sub New(ByVal dbFilePath As String)
,,FilePathInitialized = False
,,,etDbFilePath(dbFilePath)
,nd Sub
,'使用二分法查找索引區(qū),初始化查找區(qū)間
,rotected Sub Initialize()
,,,earch_Index_Set = 0
,,,earch_Index_End = Index_Count - 1
,nd Sub
,'關(guān)閉文件
,ublic Sub Dispose()
,,f (bFilePathInitialized) Then
,,,,FilePathInitialized = False
,,,,,ileStrm.Close()
,,,,,ileStrm.Dispose()
,,,nd If
,nd Sub
,'設(shè)置純真IP數(shù)據(jù)庫(kù)的文件路徑
,ublic Function SetDbFilePath(ByVal dbFilePath As String) As Boolean
,,f (dbFilePath = "") Then
,,,,,eturn False
,,,nd If
,,,'Try
,,,'打開(kāi)數(shù)據(jù)文件
,,ileStrm = New FileStream(dbFilePath, FileMode.Open, FileAccess.Read)
,,,'Catch
,,,'Return False
,,,'End Try
,,,'檢查文件長(zhǎng)度
,,f (FileStrm.Length < 8) Then
,,,,ileStrm.Close()
,,,,ileStrm.Dispose()
,,,,eturn False
,,,nd If
,,'得到第一條索引的絕對(duì)偏移和最后一條索引的絕對(duì)偏移
,,,ileStrm.Seek(0, SeekOrigin.Begin)
,,,ndex_Set = GetUInt32()
,,ndex_End = GetUInt32()
,,,'得到總索引條數(shù)
,,ndex_Count = (Index_End - Index_Set) / 7 + 1
,,,FilePathInitialized = True
,,,eturn True
,nd Function
,'主接口函數(shù),根據(jù)傳入的IP返回該IP的地址信息
,ublic Function GetAddressWithIP(ByVal IPvalue As String) As String
,,,f Not bFilePathInitialized Then
,,,,,eturn ""
,,,nd If
,,,nitialize()
,,,'將IP轉(zhuǎn)化為數(shù)字
,,im ip As UInt32 = IPToUInt32(IPvalue)
,,,hile (True)
,,,,'首先初始化本輪查找的區(qū)間
,,,,,'區(qū)間頭
,,,,,earch_Set = IndexInfoAtPos(Search_Index_Set)
,,,,,'區(qū)間尾
,,,,,earch_End = IndexInfoAtPos(Search_Index_End)
,,,,,'判斷IP是否在區(qū)間頭內(nèi)
,,,,,f (ip >= Search_Set.IpSet And ip <= Search_Set.IpEnd) Then
,,,,,,,eturn ReadAddressInfoAtOffset(Search_Set.Offset)
,,,,,nd If
,,,,,'判斷IP是否在區(qū)間尾內(nèi)
,,,,f (ip >= Search_End.IpSet And ip <= Search_End.IpEnd) Then
,,,,,,eturn ReadAddressInfoAtOffset(Search_End.Offset)
,,,,,nd If
,,,,'計(jì)算出區(qū)間中點(diǎn)
,,,,earch_Mid = IndexInfoAtPos((Search_Index_End + Search_Index_Set) / 2)
,,,,'判斷IP是否在中點(diǎn)
,,,,,f (ip >= Search_Mid.IpSet And ip <= Search_Mid.IpEnd) Then
,,,,,,,eturn ReadAddressInfoAtOffset(Search_Mid.Offset)
,,,,nd If
,,,,,'本輪沒(méi)有找到,準(zhǔn)備下一輪
,,,,,f (ip < Search_Mid.IpSet) Then
,,,,,,,'IP比區(qū)間中點(diǎn)要小,將區(qū)間尾設(shè)為現(xiàn)在的中點(diǎn),將區(qū)間縮小1倍。
,,,,,,,earch_Index_End = (Search_Index_End + Search_Index_Set) / 2
,,,,,lse
,,,,,,,'IP比區(qū)間中點(diǎn)要大,將區(qū)間頭設(shè)為現(xiàn)在的中點(diǎn),將區(qū)間縮小1倍。
,,,,,,,earch_Index_Set = (Search_Index_End + Search_Index_Set) / 2
,,,,,nd If
,,,nd While
,,,eturn ""
,nd Function
'讀取指定文件偏移位置的國(guó)家和地區(qū)信息
Protected Function ReadAddressInfoAtOffset(ByVal Offset As UInt32) As String
,,,im country As String = ""
,,im area As String = ""
,,im country_Offset As UInt32 = 0
,,im Tag As Byte = 0
,,,'跳過(guò)4字節(jié),因這4個(gè)字節(jié)是該索引的IP區(qū)間上限。
,,,ileStrm.Seek(Offset + 4, SeekOrigin.Begin)
,,,'讀取一個(gè)字節(jié),得到描述國(guó)家信息的“尋址方式”
,,,ag = GetTag()
,,,f (Tag = &H1) Then
,,,,,'模式0x01,表示接下來(lái)的3個(gè)字節(jié)是表示偏移位置
,,,,,ileStrm.Seek(GetOffset(), SeekOrigin.Begin)
,,,,'繼續(xù)檢查“尋址方式”
,,,,,ag = GetTag()
,,,,,f (Tag = &H2) Then
,,,,,,,'模式0x02,表示接下來(lái)的3個(gè)字節(jié)代表國(guó)家信息的偏移位置
,,,,,,,'先將這個(gè)偏移位置保存起來(lái),因?yàn)槲覀円x取它后面的地區(qū)信息。
,,,,,,ountry_Offset = GetOffset()
,,,,,,,'讀取地區(qū)信息(注:按照Luma的說(shuō)明,好像沒(méi)有這么多種可能性,但在測(cè)試過(guò)程中好像有些情況沒(méi)有考慮到,
,,,,,,,'所以寫(xiě)了個(gè)ReadArea()來(lái)讀取。
,,,,,,,rea = ReadArea()
,,,,,,,'讀取國(guó)家信息
,,,,,,ileStrm.Seek(country_Offset, SeekOrigin.Begin)
,,,,,,,ountry = ReadString()
,,,,,lse
,,,,,,,'這種模式說(shuō)明接下來(lái)就是保存的國(guó)家和地區(qū)信息了,以'\0'代表結(jié)束。
,,,,,,,ileStrm.Seek(-1, SeekOrigin.Current)
,,,,,,,ountry = ReadString()
,,,,,,,rea = ReadArea()
,,,,,nd If
,,,lseIf (Tag = &H2) Then
,,,,'模式0x02,說(shuō)明國(guó)家信息是一個(gè)偏移位置
,,,,,ountry_Offset = GetOffset()
,,,,'先讀取地區(qū)信息
,,,,,rea = ReadArea()
,,,,,'讀取國(guó)家信息
,,,,,ileStrm.Seek(country_Offset, SeekOrigin.Begin)
,,,,ountry = ReadString()
,,,lse
,,,,'這種模式最簡(jiǎn)單了,直接讀取國(guó)家和地區(qū)就OK了
,,,,ileStrm.Seek(-1, SeekOrigin.Current)
,,,,ountry = ReadString()
,,,,,rea = ReadArea()
,,,nd If
,,eturn country + " " + area
,nd Function
'從當(dāng)前位置讀取一個(gè)字符串(國(guó)家或者地區(qū)信息)
,rotected Function ReadString() As String
,,,im Offset As UInt32 = 0
,,,im TempByteArray(256) As Byte
,,,empByteArray(Offset) = FileStrm.ReadByte()
,,,hile (TempByteArray(Offset) <> &H0)
,,,,,ffset += 1
,,,,,empByteArray(Offset) = FileStrm.ReadByte()
,,,nd While
,,,eturn System.Text.Encoding.Default.GetString(TempByteArray)
,nd Function
,'從當(dāng)前文件位置讀取地區(qū)信息
Protected Function ReadArea() As String
,,,im Tag As Byte = GetTag()
,,,f (Tag = &H1 Or Tag = &H2) Then
,,,,,ileStrm.Seek(GetOffset(), SeekOrigin.Begin)
,,,,,eturn ReadString()
,,,lse
,,,,,ileStrm.Seek(-1, SeekOrigin.Current)
,,,,,eturn ReadString()
,,,nd If
,nd Function
,'從當(dāng)前文件位置讀取一個(gè)字節(jié)的標(biāo)識(shí)
,rotected Function GetTag() As Byte
,,eturn FileStrm.ReadByte()
End Function
,'得到指定索引位置的信息(IP起始范圍)
,rotected Function IndexInfoAtPos(ByVal Index_Pos As Int32) As CZ_INDEX_INFO
,,,im Index_Info As New CZ_INDEX_INFO
,,'根據(jù)索引編號(hào)計(jì)算出在文件中在偏移位置
,,,ileStrm.Seek(Index_Set + 7 * Index_Pos, SeekOrigin.Begin)
,,,ndex_Info.IpSet = GetUInt32()
,,,ndex_Info.Offset = GetOffset()
,,,ileStrm.Seek(Index_Info.Offset, SeekOrigin.Begin)
,,,ndex_Info.IpEnd = GetUInt32()
,,,eturn Index_Info
,nd Function
'讀取3個(gè)字節(jié),得到偏移位置
,rotected Function GetOffset() As UInt32
,,,im TempByte4(4) As Byte
,,,empByte4(0) = FileStrm.ReadByte()
,,empByte4(1) = FileStrm.ReadByte()
,,,empByte4(2) = FileStrm.ReadByte()
,,empByte4(3) = 0
,,eturn BitConverter.ToUInt32(TempByte4, 0)
,nd Function
,rotected Function GetUInt32() As UInt32
,,,im TempByte4(4) As Byte
,,,ileStrm.Read(TempByte4, 0, 4)
,,eturn BitConverter.ToUInt32(TempByte4, 0)
,nd Function
'將字符串的IP轉(zhuǎn)換成Int32
,ublic Shared Function IPToUInt32(ByVal Ipvalue As String) As UInt32
,,im IpByte() As String = Ipvalue.Split(".")
,,,im nUpperBound As Int32 = IpByte.GetUpperBound(0)
,,f nUpperBound <> 3 Then
,,,,,eDim Preserve IpByte(4)
,,,,,or i As Int32 = 1 To 3 - nUpperBound
,,,,,,,pByte(nUpperBound + i) = "0"
,,,,,ext
,,,nd If
,,,im TempByte4(4) As Byte
,,,or i As Int32 = 0 To 3
,,,,'如果是.Net 2.0可以支持TryParse。
,,,,,'If Not (Byte.TryParse(IpByte(i), TempByte4(3 - i))) Then
,,,',empByte4(3 - i) = &H0
,,,,'End If
,,,,f (IsNumeric(IpByte(i))) Then
,,,,,,,empByte4(3 - i) = CInt(IpByte(i)) And &HFF
,,,,,nd If
,,,ext
,,,eturn BitConverter.ToUInt32(TempByte4, 0)
,,,'System.Net.IPAddress.NetworkToHostOrder
,nd Function
,'將Int32型的IP轉(zhuǎn)換成字符串
Public Shared Function UInt32ToIP(ByVal UInt32value As UInt32) As String
,,,eturn New System.Net.IPAddress(System.Net.IPAddress.HostToNetworkOrder(UInt32value)).ToString()
,nd Function
End Class