Go实战--获取公网ip、查看内网ip、检测ip类型、校验ip区间、ip地址string和int转换、根据ip判断地区国家运营商

一、简要介绍net包

1. func ParseIP

func ParseIP(s string) IP

ParseIP parses s as an IP address, returning the result. The string s can be in dotted decimal (“192.0.2.1”) or IPv6 (“2001:db8::68”) form. If s is not a valid textual representation of an IP address, ParseIP returns nil.

2. func InterfaceAddrs

func InterfaceAddrs() ([]Addr, error)

InterfaceAddrs returns a list of the system’s unicast interface addresses.

The returned list does not identify the associated interface; use Interfaces and Interface.Addrs for more detail.

3. type IPNet 
An IPNet represents an IP network.

type IPNet struct {
        IP   IP     // network number
        Mask IPMask // network mask
}

4. type IP

An IP is a single IP address, a slice of bytes. Functions in this package accept either 4-byte (IPv4) or 16-byte (IPv6) slices as input.

Note that in this documentation, referring to an IP address as an IPv4 address or an IPv6 address is a semantic property of the address, not just the length of the byte slice: a 16-byte slice can still be an IPv4 address.

type IP []byte

5.func IPv4

func IPv4(a, b, c, d byte) IP

IPv4 returns the IP address (in 16-byte form) of the IPv4 address a.b.c.d.

点到为止,更详细的请看文档:https://golang.org/pkg/net。

二、什么是外网IP和内网IP?

tcp/ip协议中,专门保留了三个IP地址区域作为私有地址,其地址范围如下: 
10.0.0.0/8:10.0.0.0~10.255.255.255 
172.16.0.0/12:172.16.0.0~172.31.255.255 
192.168.0.0/16:192.168.0.0~192.168.255.255

2.1什么是内网IP

一些小型企业或者学校,通常都是申请一个固定的IP地址,然后通过IP共享(IP Sharing),使用整个公司或学校的机器都能够访问互联网。而这些企业或学校的机器使用的IP地址就是内网IP,内网IP是在规划IPv4协议时,考虑到IP地址资源可能不足,就专门为内部网设计私有IP地址(或称之为保留地址)。一般常用内网IP地址都是这种形式的:10.X.X.X、172.16.X.X-172.31.X.X、192.168.X.X等。需要注意的是,内网的计算机可向Internet上的其他计算机发送连接请求,但Internet上其他的计算机无法向内网的计算机发送连接请求。我们平时可能在内网机器上搭建过网站或者FTP服务器,而在外网是不能访问该网站和FTP服务器的,原因就在于此。

2.2什么是公网IP

公网IP就是除了保留IP地址以外的IP地址,可以与Internet上的其他计算机随意互相访问。我们通常所说的IP地址,其实就是指的公网IP。互联网上的每台计算机都有一个独立的IP地址,该IP地址唯一确定互联网上的一台计算机。这里的IP地址就是指的公网IP地址。

怎样理解互联网上的每台计算机都有一个唯一的IP地址?

其实,互联网上的计算机是通过“公网IP+内网IP”来唯一确定的。就像很多大楼都是201房间一样,房间号可能一样,但是大楼肯定是唯一的。公网IP地址和内网IP地址也是同样,不同企业或学校的机器可能有相同的内网IP地址,但是他们的公网IP地址肯定不同。那么这些企业或学校的计算机是怎样进行IP地址共享的呢?这就需要使用NAT(Network Address Translation,网络地址转换)功能。当内部计算机要连接互联网时,首先需要通过NAT技术,将内部计算机数据包中有关IP地址的设置都设成NAT主机的公共IP地址;然后再传送到Internet,虽然内部计算机使用的是私有IP地址,但在连接Internet时,就可以通过NAT主机的NAT技术,将内网IP地址修改为公网IP地址,如此一来,内网计算机就可以向Internet请求数据了。

三、获取公网ip

3.1 百度查询IP

直接在百度输入框中输入IP,即可查看公网ip。

3.2 通过http://myexternalip.com/raw获取公网IP

func getExternalIp() string {
    resp, err := http.Get("https://myexternalip.com/raw")
    if err != nil {
        return ""
    }
    defer resp.Body.Close()
    content, _ := ioutil.ReadAll(resp.Body)
    //buf := new(bytes.Buffer)
    //buf.ReadFrom(resp.Body)
    //s := buf.String()
    return string(content)
}

3.3判断是否是公网IP

func IsPublicIP(IP net.IP) bool {
	if IP.IsLoopback() || IP.IsLinkLocalMulticast() || IP.IsLinkLocalUnicast() {
		return false
	}
	if ip4 := IP.To4(); ip4 != nil {
		switch true {
		case ip4[0] == 10:
			return false
		case ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31:
			return false
		case ip4[0] == 192 && ip4[1] == 168:
			return false
		default:
			return true
		}
	}
	return false
}

四、获取本地IP

4.1 通过 net.InterfaceAddrs 获取本地IP

func getLocalIPv4s() ([]string, error) {
	var ips []string
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return ips, err
	}

	for _, a := range addrs {
		// 检查ip地址判断是否回环地址
		if ipNet, ok := a.(*net.IPNet); ok && !ipNet.IP.IsLoopback() && ipNet.IP.To4() != nil {
			ips = append(ips, ipNet.IP.String())
		}
	}

	return ips, nil
}

4.2 根据端口名称获取本地IP

func GetIPv4ByInterface(name string) ([]string, error) {
	var ips []string

	netInterface, err := net.InterfaceByName(name)
	if err != nil {
		return nil, err
	}
	//// mac物理地址
	//fmt.Println(netInterface.HardwareAddr.String())

	addrs, err := netInterface.Addrs()
	if err != nil {
		return nil, err
	}

	for _, a := range addrs {
		if ipNet, ok := a.(*net.IPNet); ok && !ipNet.IP.IsLoopback() && ipNet.IP.To4() != nil {
			ips = append(ips, ipNet.IP.String())
		}
	}

	return ips, nil
}


4.3 通过dns服务器8.8.8.8:80获取本地IP

func GetLocalIP() string {
    conn, _ := net.Dial("udp", "8.8.8.8:80")
    defer conn.Close()
    localAddr := conn.LocalAddr().String()
    idx := strings.LastIndex(localAddr, ":")
    return localAddr[0:idx]
}

五、ip地址string和int转换

5.1ip地址string转int

func inet_aton(ipnr net.IP) int64 {
	bits := strings.Split(ipnr.String(), ".")

	b0, _ := strconv.Atoi(bits[0])
	b1, _ := strconv.Atoi(bits[1])
	b2, _ := strconv.Atoi(bits[2])
	b3, _ := strconv.Atoi(bits[3])

	var sum int64

	sum += int64(b0) << 24
	sum += int64(b1) << 16
	sum += int64(b2) << 8
	sum += int64(b3)

	return sum
}

5.2 ip地址int转string

func inet_ntoa(ipnr int64) net.IP {
	var byteSlice [4]byte
	byteSlice[0] = byte(ipnr & 0xFF)
	byteSlice[1] = byte((ipnr >> 8) & 0xFF)
	byteSlice[2] = byte((ipnr >> 16) & 0xFF)
	byteSlice[3] = byte((ipnr >> 24) & 0xFF)

	return net.IPv4(byteSlice[3], byteSlice[2], byteSlice[1], byteSlice[0])
}

六、判断ip地址区间

func IpBetween(from net.IP, to net.IP, test net.IP) bool {
	if from == nil || to == nil || test == nil {
		fmt.Println("An ip input is nil") // or return an error!?
		return false
	}

	from16 := from.To16()
	to16 := to.To16()
	test16 := test.To16()
	if from16 == nil || to16 == nil || test16 == nil {
		fmt.Println("An ip did not convert to a 16 byte") // or return an error!?
		return false
	}

	if bytes.Compare(test16, from16) >= 0 && bytes.Compare(test16, to16) <= 0 {
		return true
	}
	return false
}

七、通过淘宝接口根据公网ip获取国家运营商等信息

接口: http://ip.taobao.com/service/getIpInfo.php?ip=

type IPInfo struct {
    Code int `json:"code"`
    Data IP  `json:"data`
}

type IP struct {
    Country   string `json:"country"`
    CountryId string `json:"country_id"`
    Area      string `json:"area"`
    AreaId    string `json:"area_id"`
    Region    string `json:"region"`
    RegionId  string `json:"region_id"`
    City      string `json:"city"`
    CityId    string `json:"city_id"`
    Isp       string `json:"isp"`
}

func TaobaoAPI(ip string) *IPInfo {
    url := "http://ip.taobao.com/service/getIpInfo.php?ip="
    url += ip

    resp, err := http.Get(url)
    if err != nil {
        return nil
    }
    defer resp.Body.Close()

    out, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil
    }
    var result IPInfo
    if err := json.Unmarshal(out, &result); err != nil {
        return nil
    }

    return &result
}

八、完整代码

package main

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"runtime"
	"strings"
	"strconv"
	"bytes"
	"encoding/json"
)

type IPInfo struct {
	Code int `json:"code"`
	Data IP `json:"data"`
}

type IP struct {
	Country   string `json:"country"`
	CountryId string `json:"country_id"`
	Area      string `json:"area"`
	AreaId    string `json:"area_id"`
	Region    string `json:"region"`
	RegionId  string `json:"region_id"`
	City      string `json:"city"`
	CityId    string `json:"city_id"`
	Isp       string `json:"isp"`
}

func TabaoAPI(ip string) *IPInfo {
	url := "http://ip.taobao.com/service/getIpInfo.php?ip="
	url += ip

	resp, err := http.Get(url)
	if err != nil {
		return nil
	}
	defer resp.Body.Close()

	out, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil
	}

	var result IPInfo
	if err := json.Unmarshal(out, &result); err != nil {
		return nil
	}

	return &result
}

func main() {
	arch := runtime.GOARCH
	eth := "eth0"        // 默认linux
	if "amd64" == arch { // mac架构
		eth = "en0"
	}

	// local ip
	arrIpAddr, err := getLocalIPv4s()
	if nil != err {
		fmt.Printf("err=%v", err)
	} else {
		for _, ip := range arrIpAddr {
			fmt.Println("get local ip", ip)
		}
	}

	// local ip by interface
	arrIpAddr, err = GetIPv4ByInterface(eth)
	if nil != err {
		fmt.Printf("err=%v", err)
	} else {
		for _, ip := range arrIpAddr {
			fmt.Println("get local ip by eth: ", ip)
		}
	}

	// local ip by 8:8:8:8:80
	localIp := getLocalIP()
	fmt.Println("get local ip by 8:8:8:8:80, ip=", localIp)

	isBtwnIp := IpBetween(net.ParseIP("192.168.0.1"), net.ParseIP("192.168.255.255"), net.ParseIP(localIp))
	if isBtwnIp {
		fmt.Println("Yes, local ip is in the area, ip=", localIp)
	} else {
		fmt.Println("No, local ip is not in the area, ip=", localIp)
	}

	isPublicIpAddr := IsPublicIP(net.ParseIP(localIp))
	if isPublicIpAddr {
		fmt.Println("It is public ip, ip=", localIp)
	} else {
		fmt.Println("It is not public ip, ip=", localIp)
	}

	numIp := inet_aton(net.ParseIP(localIp))
	fmt.Printf("convert ip to num, ip=%s, number=%d\n", localIp, numIp)
	originIp := inet_ntoa(numIp).String()
	fmt.Printf("convert num to ip, number=%d, ip=%s\n", numIp, originIp)

	strExternalIp := getExternalIp()
	fmt.Println("external ip: ", strExternalIp)
	isPublicIpAddr = IsPublicIP(net.ParseIP(strExternalIp))
	if isPublicIpAddr {
		fmt.Println("It is public ip, ip=", strExternalIp)
	} else {
		fmt.Println("It is not public ip, ip=", strExternalIp)
	}

	result := TabaoAPI(strExternalIp)
	// fmt.Printf("%+v\n", result)
	if result != nil {
		fmt.Println("国家:", result.Data.Country)
		fmt.Println("地区:", result.Data.Area)
		fmt.Println("城市:", result.Data.City)
		fmt.Println("运营商:", result.Data.Isp)
	}
}

// GetIPv4ByInterface return local IPv4 addresses from a specific interface name
func GetIPv4ByInterface(name string) ([]string, error) {
	var ips []string

	netInterface, err := net.InterfaceByName(name)
	if err != nil {
		return nil, err
	}
	//// mac物理地址
	//fmt.Println(netInterface.HardwareAddr.String())

	addrs, err := netInterface.Addrs()
	if err != nil {
		return nil, err
	}

	for _, a := range addrs {
		if ipNet, ok := a.(*net.IPNet); ok && !ipNet.IP.IsLoopback() && ipNet.IP.To4() != nil {
			ips = append(ips, ipNet.IP.String())
		}
	}

	return ips, nil
}

// getLocalIPv4s return all local non-loopback IPv4 addresses
func getLocalIPv4s() ([]string, error) {
	var ips []string
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return ips, err
	}

	for _, a := range addrs {
		// 检查ip地址判断是否回环地址
		if ipNet, ok := a.(*net.IPNet); ok && !ipNet.IP.IsLoopback() && ipNet.IP.To4() != nil {
			ips = append(ips, ipNet.IP.String())
		}
	}

	return ips, nil
}

func getLocalIP() string {
	conn, _ := net.Dial("udp", "8.8.8.8:80")
	defer conn.Close()
	localAddr := conn.LocalAddr().String()
	//fmt.Println("localAddr", localAddr)
	idx := strings.LastIndex(localAddr, ":")
	return localAddr[0:idx]
}

func getExternalIp() string {
	resp, err := http.Get("https://myexternalip.com/raw")
	if err != nil {
		fmt.Println("get external ip err=", err)
		return ""
	}
	defer resp.Body.Close()
	content, _ := ioutil.ReadAll(resp.Body)
	//buf := new(bytes.Buffer)
	//buf.ReadFrom(resp.Body)
	//s := buf.String()
	return string(content)
}

func IsPublicIP(IP net.IP) bool {
	if IP.IsLoopback() || IP.IsLinkLocalMulticast() || IP.IsLinkLocalUnicast() {
		return false
	}
	if ip4 := IP.To4(); ip4 != nil {
		switch true {
		case ip4[0] == 10:
			return false
		case ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31:
			return false
		case ip4[0] == 192 && ip4[1] == 168:
			return false
		default:
			return true
		}
	}
	return false
}

func inet_aton(ipnr net.IP) int64 {
	bits := strings.Split(ipnr.String(), ".")

	b0, _ := strconv.Atoi(bits[0])
	b1, _ := strconv.Atoi(bits[1])
	b2, _ := strconv.Atoi(bits[2])
	b3, _ := strconv.Atoi(bits[3])

	var sum int64

	sum += int64(b0) << 24
	sum += int64(b1) << 16
	sum += int64(b2) << 8
	sum += int64(b3)

	return sum
}

func inet_ntoa(ipnr int64) net.IP {
	var byteSlice [4]byte
	byteSlice[0] = byte(ipnr & 0xFF)
	byteSlice[1] = byte((ipnr >> 8) & 0xFF)
	byteSlice[2] = byte((ipnr >> 16) & 0xFF)
	byteSlice[3] = byte((ipnr >> 24) & 0xFF)

	return net.IPv4(byteSlice[3], byteSlice[2], byteSlice[1], byteSlice[0])
}

func IpBetween(from net.IP, to net.IP, test net.IP) bool {
	if from == nil || to == nil || test == nil {
		fmt.Println("An ip input is nil")
		return false
	}

	from16 := from.To16()
	to16 := to.To16()
	test16 := test.To16()
	if from16 == nil || to16 == nil || test16 == nil {
		fmt.Println("An ip did not convert to a 16 byte")
		return false
	}

	if bytes.Compare(test16, from16) >= 0 && bytes.Compare(test16, to16) <= 0 {
		return true
	}
	return false
}

运行结果如下所示:

展开阅读全文

没有更多推荐了,返回首页