现在很多网络应用已经都在展示网友的IP归属地,通过golang以及qqzengIP地址库,可以很方便的实现这个功能

package toolsimport ("io/ioutil""log""strconv""strings"
)/*** @author xiao.luo* @description This is the go version for IpSearch*/
type CityInfo struct {CountryName string `json:"country_name"`RegionName  string `json:"region_name"`CityName    string `json:"city_name"`AreaName    string `json:"area_name"`
}
type ipIndex struct {startip, endip             uint32local_offset, local_length uint32
}type prefixIndex struct {start_index, end_index uint32
}type ipSearch struct {data               []byteprefixMap          map[uint32]prefixIndexfirstStartIpOffset uint32prefixStartOffset  uint32prefixEndOffset    uint32prefixCount        uint32
}var ips *ipSearch = nilfunc NewIpdb(ipPath string) (ipSearch, error) {if ips == nil {var err errorips, err = loadIpDat(ipPath)if err != nil {log.Fatal("the IP Dat loaded failed!")return *ips, err}}return *ips, nil
}func loadIpDat(ipPath string) (*ipSearch, error) {p := ipSearch{}//加载ip地址库信息data, err := ioutil.ReadFile(ipPath)if err != nil {log.Fatal(err)}p.data = datap.prefixMap = make(map[uint32]prefixIndex)p.firstStartIpOffset = bytesToLong(data[0], data[1], data[2], data[3])p.prefixStartOffset = bytesToLong(data[8], data[9], data[10], data[11])p.prefixEndOffset = bytesToLong(data[12], data[13], data[14], data[15])p.prefixCount = (p.prefixEndOffset-p.prefixStartOffset)/9 + 1 // 前缀区块每组// 初始化前缀对应索引区区间indexBuffer := p.data[p.prefixStartOffset:(p.prefixEndOffset + 9)]for k := uint32(0); k < p.prefixCount; k++ {i := k * 9prefix := uint32(indexBuffer[i] & 0xFF)pf := prefixIndex{}pf.start_index = bytesToLong(indexBuffer[i+1], indexBuffer[i+2], indexBuffer[i+3], indexBuffer[i+4])pf.end_index = bytesToLong(indexBuffer[i+5], indexBuffer[i+6], indexBuffer[i+7], indexBuffer[i+8])p.prefixMap[prefix] = pf}return &p, nil
}func (p ipSearch) Get(ip string) string {ips := strings.Split(ip, ".")x, _ := strconv.Atoi(ips[0])prefix := uint32(x)intIP := ipToLong(ip)var high uint32 = 0var low uint32 = 0if _, ok := p.prefixMap[prefix]; ok {low = p.prefixMap[prefix].start_indexhigh = p.prefixMap[prefix].end_index} else {return ""}var my_index uint32if low == high {my_index = low} else {my_index = p.binarySearch(low, high, intIP)}ipindex := ipIndex{}ipindex.getIndex(my_index, &p)if ipindex.startip <= intIP && ipindex.endip >= intIP {return ipindex.getLocal(&p)} else {return ""}
}// 二分逼近算法
func (p ipSearch) binarySearch(low uint32, high uint32, k uint32) uint32 {var M uint32 = 0for low <= high {mid := (low + high) / 2endipNum := p.getEndIp(mid)if endipNum >= k {M = midif mid == 0 {break // 防止溢出}high = mid - 1} else {low = mid + 1}}return M
}// 只获取结束ip的数值
// 索引区第left个索引
// 返回结束ip的数值
func (p ipSearch) getEndIp(left uint32) uint32 {left_offset := p.firstStartIpOffset + left*12return bytesToLong(p.data[4+left_offset], p.data[5+left_offset], p.data[6+left_offset], p.data[7+left_offset])}func (p *ipIndex) getIndex(left uint32, ips *ipSearch) {left_offset := ips.firstStartIpOffset + left*12p.startip = bytesToLong(ips.data[left_offset], ips.data[1+left_offset], ips.data[2+left_offset], ips.data[3+left_offset])p.endip = bytesToLong(ips.data[4+left_offset], ips.data[5+left_offset], ips.data[6+left_offset], ips.data[7+left_offset])p.local_offset = bytesToLong3(ips.data[8+left_offset], ips.data[9+left_offset], ips.data[10+left_offset])p.local_length = uint32(ips.data[11+left_offset])
}// / 返回地址信息
// / 地址信息的流位置
// / 地址信息的流长度
func (p *ipIndex) getLocal(ips *ipSearch) string {bytes := ips.data[p.local_offset : p.local_offset+p.local_length]return string(bytes)}func ipToLong(ip string) uint32 {quads := strings.Split(ip, ".")if len(quads) < 4 {return 0}var result uint32 = 0a, _ := strconv.Atoi(quads[3])result += uint32(a)b, _ := strconv.Atoi(quads[2])result += uint32(b) << 8c, _ := strconv.Atoi(quads[1])result += uint32(c) << 16d, _ := strconv.Atoi(quads[0])result += uint32(d) << 24return result
}//字节转整形
func bytesToLong(a, b, c, d byte) uint32 {a1 := uint32(a)b1 := uint32(b)c1 := uint32(c)d1 := uint32(d)return (a1 & 0xFF) | ((b1 << 8) & 0xFF00) | ((c1 << 16) & 0xFF0000) | ((d1 << 24) & 0xFF000000)
}func bytesToLong3(a, b, c byte) uint32 {a1 := uint32(a)b1 := uint32(b)c1 := uint32(c)return (a1 & 0xFF) | ((b1 << 8) & 0xFF00) | ((c1 << 16) & 0xFF0000)}

针对上面的代码进行单元测试

package toolsimport ("log""strings""testing"
)func TestNewIpdb(t *testing.T) {var ip, ipstr stringvar infos []stringp, _ := NewIpdb("../config/qqzeng-ip-utf8.dat")ip = "113.104.209.240"ipstr = p.Get(ip)infos = strings.Split(ipstr, "|")log.Println(infos)ip = "39.155.215.54"ipstr = p.Get(ip)infos = strings.Split(ipstr, "|")log.Println(infos)ip = "127.0.0.1"ipstr = p.Get(ip)infos = strings.Split(ipstr, "|")log.Println(infos)ip = "192.168.1.1"ipstr = p.Get(ip)infos = strings.Split(ipstr, "|")log.Println(infos)
}

2023/03/03 15:49:48 [亚洲 中国 广东 深圳 宝安 电信 440306 China CN 113.88311 22.55371]
2023/03/03 15:49:48 [亚洲 中国 北京 北京  移动 110100 China CN 116.405285 39.904989]
2023/03/03 15:49:48 [ 保留         ]
2023/03/03 15:49:48 [ 保留         ]

另外,有客服系统需求的同学,可以访问下面地址研究测试

gofly.v1kf.com 产品官网

golang实现IP地址转归属地国家、省份、城市、获取网络运营商-在线客服系统获取访客地址功能【唯一客服】...相关推荐

  1. 最新IP数据库-基于国家省份城市县区和运营商-专业准确-每月发行

    最新IP地址数据库(qqzeng-ip) 2023年6月 最新发行版 992003 条数据 版本:全球旗舰版(国内精华版+国外拓展版) 基于:国内基于省市区以及运营商 国外基于国家 部分到大城市和运营 ...

  2. 修改QQ资料国家,省份,城市为空

    最新修改QQ资料国家,省份,城市为空的方法 打开默认就填上了 好多人都想把QQ资料中的国家.城市有的人都是这样 "首先我们要准备的工具是 腾讯QQ2008 贺岁版(没有的去百度搜下) 年龄也 ...

  3. java IP转换为国家省份城市

    日萌社 人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新) 参考文章:https://blog.csdn.net/chws ...

  4. 国家省份城市级联菜单

    <html> <head> <title>级联菜单</title> <meta http-equiv="Content-Type&quo ...

  5. 【java】使用ip获取 国家 省份 城市

    1.下载GeoLite2 City库 下载地址: http://dev.maxmind.com/geoip/geoip2/geolite2/ https://download.csdn.net/dow ...

  6. 世界国家省份城市县区街道村地址邮编常用通用功能最全API - 多级联动 - 淘宝天猫阿里巴巴技术赏析...

    请登录购买宝贝并到结帐页面 http://unit.buy.tmall.com/order/confirmOrder.htm 当到这个页面后,你会发现这个页面是个iframe(框架),单击右键可以轻松 ...

  7. js 获取当前国家 省份 城市等信息

    引入jquery.js$.getScript('http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js',function(){ale ...

  8. Java 获取ip地址、省份城市、城市ip

    1.获取ip :使用request.getHeader("x-forwarded-for")获取真实IP,x-forwarded-for的值并不止一个,而是一串IP值,获取为空时, ...

  9. php ip获取邮政编码,php获取指定(访客)IP所有信息(地址、邮政编码、国家、经纬度等)的方法...

    这篇文章主要介绍了php获取指定(访客)IP所有信息(地址.邮政编码.国家.经纬度等)的方法,通过一个API接口调用实现针对访客信息的相关查询功能,非常简单实用, 本文实例讲述了php获取指定(访客) ...

最新文章

  1. 砥砺前行:我的2016总结和2017计划 | 掘金技术征文
  2. html,css,js,反弹的js效果
  3. Mysql生产指定时间段随机日期函数
  4. 网页MSN,QQ,Skype,贸易通,雅虎通在线客服代码合集
  5. python zipfile压缩_Python压缩模块zipfile实现原理及用法解析
  6. libevent: linux安装libevent
  7. 防saq注入_去中心化交易所CYBEX将为区块链ICO注入新的价值观
  8. 五分钟学会python_关于五分钟学Python系列视频
  9. 百度实习笔试题(2012.5.6)
  10. CSDN《老友记》简记
  11. 2022 AAAI 多模态/情感分析/命名实体识别/(信息抽取)关系抽取/知识图谱(知识蒸馏)/阅读理解 论文一览表
  12. POI合并单元格,赋值
  13. 利用服务器在家远程登录办公室电脑
  14. java web play_玩转 Java Web 应用开发:Play 框架
  15. ariang/Aria2 RPC 服务器错误/Aria2状态/未连接
  16. 智能、精准、节能丨极海APM32F103RCT7 LED车灯应用方案
  17. ChatGPT所代表的人工智能的意义
  18. 笔记:C#_委托_delegate
  19. 5g工业千兆路由器_wifi路由器
  20. Dota之后,《王者荣耀》也被AI攻陷,势把人类顶级玩家拉下马

热门文章

  1. 计算机3d影视的应用程序,用电脑也能看3D电影?捡起吃灰的3D眼镜!
  2. CSS设置背景颜色 拼接 (一半黑一半白) 条纹 渐变
  3. 关于 UGUI 字体花屏或乱码。
  4. 前端 谷歌 chorme f12开发者工具调试技巧
  5. [计划安排] 408经验帖(转自某大神)
  6. Kotlin系列四:标准函数、扩展函数、高阶函数、内联函数
  7. ORB-SLAM2的源码阅读(一):系统的整体构建
  8. Android应用接入第三方登陆之新浪微博
  9. 【建站】分分钟带你建立自己的专属网站
  10. 从零开始搭建微服务:认证服务器