生命不止,繼續 go go go。。。
之前,有介紹過golang提供的標準庫:net包
Go語言學習之net包(The way to go) 簡要回味net包
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.
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.
type IPNet
An IPNet represents an IP network.
type IPNet struct { IP IP // network number Mask IPMask // network mask}
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
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
什麼是內網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伺服器的,原因就在於此。
什麼是公網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
百度ip,即可查看公網ip
curl命令查看公網ip
curl ipinfo.io/ip
通過http://myexternalip.com/raw擷取公網ip
func get_external() string { resp, err := http.Get("http://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)}
擷取本地ip
func GetIntranetIp() { addrs, err := net.InterfaceAddrs() if err != nil { fmt.Println(err) os.Exit(1) } for _, address := range addrs { // 檢查ip地址判斷是否迴環地址 if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { if ipnet.IP.To4() != nil { fmt.Println("ip:", ipnet.IP.String()) } } }}
通過dns伺服器8.8.8.8:80擷取使用的ip
func GetPulicIP() 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
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地址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}
ip地址int轉string
func inet_ntoa(ipnr int64) net.IP { var bytes [4]byte bytes[0] = byte(ipnr & 0xFF) bytes[1] = byte((ipnr >> 8) & 0xFF) bytes[2] = byte((ipnr >> 16) & 0xFF) bytes[3] = byte((ipnr >> 24) & 0xFF) return net.IPv4(bytes[3], bytes[2], bytes[1], bytes[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 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}
完整代碼
package mainimport ( "bytes" "encoding/json" "fmt" "io/ioutil" "net" "net/http" "os" "strconv" "strings")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 main() { external_ip := get_external() external_ip = strings.Replace(external_ip, "\n", "", -1) fmt.Println("公網ip是: ", external_ip) fmt.Println("------Dividing Line------") ip := net.ParseIP(external_ip) if ip == nil { fmt.Println("您輸入的不是有效IP地址,請重新輸入。") } else { result := TabaoAPI(string(external_ip)) if result != nil { fmt.Println("國家:", result.Data.Country) fmt.Println("地區:", result.Data.Area) fmt.Println("城市:", result.Data.City) fmt.Println("電訊廠商:", result.Data.Isp) } } fmt.Println("------Dividing Line------") GetIntranetIp() fmt.Println("------Dividing Line------") ip_int := inet_aton(net.ParseIP(external_ip)) fmt.Println("Convert IPv4 address to decimal number(base 10) :", ip_int) ip_result := inet_ntoa(ip_int) fmt.Println("Convert decimal number(base 10) to IPv4 address:", ip_result) fmt.Println("------Dividing Line------") is_between := IpBetween(net.ParseIP("0.0.0.0"), net.ParseIP("255.255.255.255"), net.ParseIP(external_ip)) fmt.Println("check result: ", is_between) fmt.Println("------Dividing Line------") is_public_ip := IsPublicIP(net.ParseIP(external_ip)) fmt.Println("It is public ip: ", is_public_ip) is_public_ip = IsPublicIP(net.ParseIP("169.254.85.131")) fmt.Println("It is public ip: ", is_public_ip) fmt.Println("------Dividing Line------") fmt.Println(GetPulicIP())}func get_external() string { resp, err := http.Get("http://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)}func GetIntranetIp() { addrs, err := net.InterfaceAddrs() if err != nil { fmt.Println(err) os.Exit(1) } for _, address := range addrs { // 檢查ip地址判斷是否迴環地址 if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { if ipnet.IP.To4() != nil { fmt.Println("ip:", ipnet.IP.String()) } } }}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 inet_ntoa(ipnr int64) net.IP { var bytes [4]byte bytes[0] = byte(ipnr & 0xFF) bytes[1] = byte((ipnr >> 8) & 0xFF) bytes[2] = byte((ipnr >> 16) & 0xFF) bytes[3] = byte((ipnr >> 24) & 0xFF) return net.IPv4(bytes[3], bytes[2], bytes[1], bytes[0])}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 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}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 GetPulicIP() 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是: 222.128.17*.***------Dividing Line------國家: 中國地區: 華北城市: 北京市電訊廠商: 聯通------Dividing Line------ip: 169.254.85.131ip: 169.254.64.29ip: 169.254.211.178ip: 192.168.106.1ip: 192.168.154.1ip: 169.254.212.223ip: 192.168.10.26ip: 169.254.63.20------Dividing Line------Convert IPv4 address to decimal number(base 10) : 373297****Convert decimal number(base 10) to IPv4 address: 222.128.17*.***------Dividing Line------check result: true------Dividing Line------It is public ip: trueIt is public ip: false------Dividing Line------192.168.10.26