mirror of
https://github.com/lionsoul2014/ip2region.git
synced 2025-12-08 19:25:22 +00:00
193 lines
5.1 KiB
Python
193 lines
5.1 KiB
Python
#-*- coding:utf-8 -*-
|
|
"""
|
|
" ip2region python seacher client module
|
|
"
|
|
" Autho: koma<komazhang@foxmail.com>
|
|
" Date : 2015-11-06
|
|
"""
|
|
import struct, io, socket, sys
|
|
|
|
class Ip2Region(object):
|
|
__headerSip = []
|
|
__headerPtr = []
|
|
__f = None
|
|
|
|
def __init__(self, dbfile):
|
|
self.initDatabase(dbfile)
|
|
|
|
def binarySearch(self, ip):
|
|
"""
|
|
" binary search method
|
|
" param: ip
|
|
"""
|
|
if not ip.isdigit(): ip = self.ip2long(ip)
|
|
|
|
self.__f.seek(0)
|
|
b = self.__f.read(8)
|
|
startPtr = self.getLong(b, 0)
|
|
endPtr = self.getLong(b, 4)
|
|
|
|
indexLen = endPtr - startPtr
|
|
self.__f.seek(startPtr)
|
|
b = self.__f.read(indexLen+12)
|
|
|
|
l, h, mixPtr = (0, int(indexLen/12), 0)
|
|
while l <= h:
|
|
m = int((l+h)/2)
|
|
ptr = startPtr + m*12
|
|
self.__f.seek(ptr)
|
|
|
|
b = self.__f.read(12)
|
|
sip = self.getLong(b, 0)
|
|
eip = self.getLong(b, 4)
|
|
|
|
if ip > sip:
|
|
if ip > eip:
|
|
l = m + 1
|
|
else:
|
|
mixPtr = self.getLong(b, 8)
|
|
break;
|
|
else:
|
|
h = m - 1
|
|
|
|
if mixPtr == 0: return "N2"
|
|
|
|
dataPtr = mixPtr & 0x00FFFFFFL
|
|
dataLen = (mixPtr >> 24) & 0xFF
|
|
|
|
self.__f.seek(dataPtr)
|
|
data = self.__f.read(dataLen)
|
|
return {
|
|
"city_id": self.getLong(data, 0),
|
|
"region" : data[4:]
|
|
}
|
|
|
|
def btreeSearch(self, ip):
|
|
"""
|
|
" b-tree search method
|
|
" param: ip
|
|
"""
|
|
if not ip.isdigit(): ip = self.ip2long(ip)
|
|
|
|
headerLen = len(self.__headerSip) - 1
|
|
l, h, sptr, eptr = (0, headerLen, 0, 0)
|
|
while l <= h:
|
|
m = int((l+h)/2)
|
|
|
|
if ip == self.__headerSip[m]:
|
|
if m > 0:
|
|
sptr = self.__headerPtr[m-1]
|
|
eptr = self.__headerPtr[m]
|
|
break;
|
|
else:
|
|
sptr = self.__headerPtr[m]
|
|
eptr = self.__headerPtr[m+1]
|
|
break;
|
|
|
|
if ip > self.__headerSip[m]:
|
|
if m == headerLen:
|
|
sptr = self.__headerPtr[m-1]
|
|
eptr = self.__headerPtr[m]
|
|
break;
|
|
elif ip < self.__headerSip[m+1]:
|
|
sptr = self.__headerPtr[m]
|
|
eptr = self.__headerPtr[m+1]
|
|
break;
|
|
|
|
l = m + 1
|
|
else:
|
|
if m == 0:
|
|
sptr = self.__headerPtr[m]
|
|
eptr = self.__headerPtr[m+1]
|
|
break;
|
|
elif ip > self.__headerSip[m-1]:
|
|
sptr = self.__headerPtr[m-1]
|
|
eptr = self.__headerPtr[m]
|
|
break;
|
|
|
|
h = m - 1
|
|
|
|
if sptr == 0: return "N1"
|
|
|
|
indexLen = eptr - sptr
|
|
self.__f.seek(sptr)
|
|
b = self.__f.read(indexLen + 12)
|
|
|
|
l, h, mixPtr = (0, int(indexLen/12), 0)
|
|
while l <= h:
|
|
m = int((l+h)/2)
|
|
offset = m * 12
|
|
|
|
if ip > self.getLong(b, offset):
|
|
if ip > self.getLong(b, offset+4):
|
|
l = m + 1
|
|
else:
|
|
mixPtr = self.getLong(b, offset+8)
|
|
break;
|
|
else:
|
|
h = m - 1
|
|
|
|
if mixPtr == 0: return "N2"
|
|
|
|
dataPtr = mixPtr & 0x00FFFFFFL
|
|
dataLen = (mixPtr >> 24) & 0xFF
|
|
|
|
self.__f.seek(dataPtr)
|
|
data = self.__f.read(dataLen)
|
|
return {
|
|
"city_id": self.getLong(data, 0),
|
|
"region" : data[4:]
|
|
}
|
|
|
|
def initDatabase(self, dbfile):
|
|
"""
|
|
" initialize the database for search
|
|
" param: dbFile
|
|
"""
|
|
try:
|
|
self.__f = io.open(dbfile, "rb")
|
|
#pass the super block
|
|
self.__f.seek(8)
|
|
#read the header block
|
|
b = self.__f.read(4086)
|
|
#parse the header block
|
|
sip = None
|
|
ptr = None
|
|
for i in range(0, len(b)-1, 8):
|
|
sip = self.getLong(b, i)
|
|
ptr = self.getLong(b, i+4)
|
|
if ptr == 0:
|
|
break
|
|
self.__headerSip.append(sip)
|
|
self.__headerPtr.append(ptr)
|
|
|
|
except IOError, e:
|
|
print "[Error]: ", e
|
|
sys.exit()
|
|
|
|
def ip2long(self, ip):
|
|
_ip = socket.inet_aton(ip)
|
|
return struct.unpack("!L", _ip)[0]
|
|
|
|
def isip(self, ip):
|
|
p = ip.split(".")
|
|
|
|
if len(p) != 4 : return False
|
|
for pp in p:
|
|
if not pp.isdigit(): return False
|
|
if len(pp) > 3 : return False
|
|
if int(pp) > 255 : return False
|
|
|
|
return True
|
|
|
|
def getLong(self, b, offset):
|
|
if len( b[offset:offset+4] ) == 4:
|
|
return struct.unpack('I', b[offset:offset+4])[0]
|
|
return 0
|
|
|
|
def close(self):
|
|
self.__headerSip = None
|
|
self.__headerPtr = None
|
|
self.__f.close()
|
|
self.__f = None
|