diff --git a/README.md b/README.md index b572284..3bad693 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ Golang QQWry,高性能纯真IP查询库。 # 使用须知 1. 仅支持ipv4查询。 -2. city也可能是国家。 # 使用说明 @@ -13,8 +12,8 @@ Golang QQWry,高性能纯真IP查询库。 package main import ( + "fmt" "github.com/xiaoqidun/qqwry" - "log" ) func main() { @@ -23,8 +22,18 @@ func main() { panic(err) } // 从内存或缓存查询IP - city, isp, err := qqwry.QueryIP("1.1.1.1") - log.Printf("城市:%s,运营商:%s,错误:%v", city, isp, err) + location, err := qqwry.QueryIP("119.29.29.29") + if err != nil { + fmt.Printf("错误:%v\n", err) + return + } + fmt.Printf("国家:%s,省份:%s,城市:%s,区县:%s,运营商:%s\n", + location.Country, + location.Province, + location.City, + location.District, + location.ISP, + ) } ``` @@ -42,7 +51,7 @@ func main() { 1. 自行根据需要调整server下源码。 2. 可以通过-listen参数指定http服务地址。 -3. json api:curl http://127.0.0.1/ip/1.1.1.1 +3. json api:curl http://127.0.0.1/ip/119.29.29.29 # 特别感谢 diff --git a/client/client.go b/client/client.go index f3194bf..9d995af 100644 --- a/client/client.go +++ b/client/client.go @@ -16,10 +16,22 @@ func main() { return } queryIp := os.Args[1] - city, isp, err := qqwry.QueryIP(queryIp) + location, err := qqwry.QueryIP(queryIp) if err != nil { fmt.Printf("错误:%v\n", err) return } - fmt.Printf("城市:%s,运营商:%s\n", city, isp) + emptyVal := func(val string) string { + if val != "" { + return val + } + return "未知" + } + fmt.Printf("国家:%s,省份:%s,城市:%s,区县:%s,运营商:%s\n", + emptyVal(location.Country), + emptyVal(location.Province), + emptyVal(location.City), + emptyVal(location.District), + emptyVal(location.ISP), + ) } diff --git a/qqwry.go b/qqwry.go index aaef853..a487b07 100644 --- a/qqwry.go +++ b/qqwry.go @@ -14,9 +14,9 @@ import ( ) var ( - data []byte - dataLen uint32 - ipCache = &sync.Map{} + data []byte + dataLen uint32 + locationCache = &sync.Map{} ) const ( @@ -25,9 +25,13 @@ const ( redirectMode2 = 0x02 ) -type cache struct { - City string - Isp string +type Location struct { + Country string // 国家 + Province string // 省份 + City string // 城市 + District string // 区县 + ISP string // 运营商 + IP string // IP地址 } func byte3ToUInt32(data []byte) uint32 { @@ -45,16 +49,13 @@ func gb18030Decode(src []byte) string { } // QueryIP 从内存或缓存查询IP -func QueryIP(queryIp string) (city string, isp string, err error) { - if v, ok := ipCache.Load(queryIp); ok { - city = v.(cache).City - isp = v.(cache).Isp - return +func QueryIP(ipv4 string) (location *Location, err error) { + if v, ok := locationCache.Load(ipv4); ok { + return v.(*Location), nil } - ip := net.ParseIP(queryIp).To4() + ip := net.ParseIP(ipv4).To4() if ip == nil { - err = errors.New("ip is not ipv4") - return + return nil, errors.New("ip is not ipv4") } ip32 := binary.BigEndian.Uint32(ip) posA := binary.LittleEndian.Uint32(data[:4]) @@ -84,12 +85,12 @@ func QueryIP(queryIp string) (city string, isp string, err error) { } } if offset <= 0 { - err = errors.New("ip not found") - return + return nil, errors.New("ip not found") } posM := offset + 4 mode := data[posM] var ispPos uint32 + var addr, isp string switch mode { case redirectMode1: posC := byte3ToUInt32(data[posM+1 : posM+4]) @@ -101,19 +102,19 @@ func QueryIP(queryIp string) (city string, isp string, err error) { } for i := posCA; i < dataLen; i++ { if data[i] == 0 { - city = string(data[posCA:i]) + addr = string(data[posCA:i]) break } } if mode != redirectMode2 { - posC += uint32(len(city) + 1) + posC += uint32(len(addr) + 1) } ispPos = posC case redirectMode2: posCA := byte3ToUInt32(data[posM+1 : posM+4]) for i := posCA; i < dataLen; i++ { if data[i] == 0 { - city = string(data[posCA:i]) + addr = string(data[posCA:i]) break } } @@ -122,14 +123,14 @@ func QueryIP(queryIp string) (city string, isp string, err error) { posCA := offset + 4 for i := posCA; i < dataLen; i++ { if data[i] == 0 { - city = string(data[posCA:i]) + addr = string(data[posCA:i]) break } } - ispPos = offset + uint32(5+len(city)) + ispPos = offset + uint32(5+len(addr)) } - if city != "" { - city = strings.TrimSpace(gb18030Decode([]byte(city))) + if addr != "" { + addr = strings.TrimSpace(gb18030Decode([]byte(addr))) } ispMode := data[ispPos] if ispMode == redirectMode1 || ispMode == redirectMode2 { @@ -150,8 +151,9 @@ func QueryIP(queryIp string) (city string, isp string, err error) { } } } - ipCache.Store(queryIp, cache{City: city, Isp: isp}) - return + location = SplitResult(addr, isp, ipv4) + locationCache.Store(ipv4, location) + return location, nil } // LoadData 从内存加载IP数据库 @@ -169,3 +171,22 @@ func LoadFile(filepath string) (err error) { dataLen = uint32(len(data)) return } + +// SplitResult 按照调整后的纯真社区版IP库地理位置格式返回结果 +func SplitResult(addr string, isp string, ipv4 string) (location *Location) { + location = &Location{ISP: isp, IP: ipv4} + splitList := strings.Split(addr, "–") + for i := 0; i < len(splitList); i++ { + switch i { + case 0: + location.Country = splitList[i] + case 1: + location.Province = splitList[i] + case 2: + location.City = splitList[i] + case 3: + location.District = splitList[i] + } + } + return +} diff --git a/qqwry_test.go b/qqwry_test.go index b3c2fdb..5b7d7ed 100644 --- a/qqwry_test.go +++ b/qqwry_test.go @@ -11,10 +11,22 @@ func init() { } func TestQueryIP(t *testing.T) { - queryIp := "1.1.1.1" - city, isp, err := QueryIP(queryIp) + queryIp := "119.29.29.29" + location, err := QueryIP(queryIp) if err != nil { t.Fatal(err) } - t.Logf("城市:%s,运营商:%s", city, isp) + emptyVal := func(val string) string { + if val != "" { + return val + } + return "未知" + } + t.Logf("国家:%s,省份:%s,城市:%s,区县:%s,运营商:%s", + emptyVal(location.Country), + emptyVal(location.Province), + emptyVal(location.City), + emptyVal(location.District), + emptyVal(location.ISP), + ) } diff --git a/server/server.go b/server/server.go index 25d6f87..b881036 100644 --- a/server/server.go +++ b/server/server.go @@ -10,10 +10,9 @@ import ( ) type resp struct { - IP string `json:"ip"` - Err string `json:"err"` - City string `json:"city"` - Isp string `json:"isp"` + Data *qqwry.Location `json:"data"` + Success bool `json:"success"` + Message string `json:"message"` } func init() { @@ -34,14 +33,14 @@ func IpAPI(writer http.ResponseWriter, request *http.Request) { if ip == "" { ip, _, _ = net.SplitHostPort(request.RemoteAddr) } - rw := &resp{IP: ip} - city, isp, err := qqwry.QueryIP(ip) + write := &resp{} + location, err := qqwry.QueryIP(ip) if err != nil { - rw.Err = err.Error() + write.Message = err.Error() } else { - rw.City = city - rw.Isp = isp + write.Data = location + write.Success = true } - b, _ := json.MarshalIndent(rw, "", " ") + b, _ := json.MarshalIndent(write, "", " ") _, _ = writer.Write(b) }