店铺网络自检程序(Go语言)

公司开发的播放软件在某些店铺使用时出现播放卡顿的现象,店员使用360网络自检工具测试,结果显示正常,播放QQ音乐或者网易音乐也是正常的,领导层认为是开发团队的问题,于是和客户一对一沟通提供技术支持,最终确认客户网络使用自建DNS服务器,店铺DNS主服务器在广州,主服务器设置的DNS配置访问我们使用的CDN会出现延迟高的情况。

为了测试其他几百家店铺是否有相同的问题,用Go语言开发了网络自检程序,因为Go语言可以直接生成二进制可执行文件,对各个类型的操作系统都适用,店铺拿到程序双击运行即可,免去了装虚拟机和运行时环境的繁琐。

程序分几个步骤检测网络环境:

  1. 下载我公司提供的CDN加速后文件,下载后比对是否完整,计算下载时间
  2. 下载竞品的CDN加速后文件,计算下载时间
  3. 本地ip地址
  4. 公网ip地址
  5. traceroute到我公司的文件服务器地址,记录整个路由链路
  6. 将信息通过邮件方式上报到开发人员的邮箱

代码如下:

package main

import (
	"bufio"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/go-basic/ipv4"
	"github.com/go-mail/mail"
	"github.com/go-ping/ping"
	"golang.org/x/text/encoding/simplifiedchinese"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"strconv"
	"strings"
	"time"
)

var content string
var urls = [...]string{"www.lavaradio.com", "api-safe-pro.lavaradio.com", "static01.lavaradio.com", "img01.lavaradio.com", "audio01.dmhmusic.com", "audio02.dmhmusic.com", "audio03.dmhmusic.com", "audio04.dmhmusic.com"}
var mp3_urls = [...]string{"https://ws.stream.qqmusic.qq.com/C400003OSSk60F2Vvx.m4a?guid=7533888128&vkey=1C75FDFE9076A5C120FD01D9393BCAA7420E418C5D43A8CD60691D73A72E217E613BAA8C88EE2316F1260CB420DED3C7642AC175265CCF9C&uin=0&fromtag=66",
	"http://audio04.dmhmusic.com/73_16_T10054723832_128_4_1_0_sdk-cpm/cn/0103/M00/F7/F4/ChR45V7CdUWAf2I1ACPH89lgI14122.mp3?xcode=dfbdb4a731997a1b7841b75aeadf4f7a4c1c446"}
var ping_time int = 10
var ping_timeout time.Duration = time.Second * 10
var sysType string = runtime.GOOS

func main() {
	ip := ipv4.LocalIP()
	content = "======= Detection of network state begin =======" + "\n"
	content += "Local ip address: " + ip
	content += "\n"
	getExternalIp()
	defer sendBack()
	defer download()
	defer getTracert()
	defer goPing()
	defer getDns()
}

func goPing() {
	content += "\n"
	content += "=== Ping test begin ==="
	for i, v := range urls {
		pinger, err := ping.NewPinger(v)
		if sysType == "windows" {
			pinger.SetPrivileged(true)
		}
		pinger.Count = ping_time
		pinger.Timeout = ping_timeout
		if err != nil {
			content += "Error: " + err.Error() + "\n"
			fmt.Printf(err.Error())
		}

		// listen for ctrl-C signal
		c := make(chan os.Signal, 1)
		signal.Notify(c, os.Interrupt)
		go func() {
			for _ = range c {
				pinger.Stop()
			}
		}()

		pinger.OnRecv = func(pkt *ping.Packet) {
			fmt.Printf("%d bytes from %s: icmp_seq=%d time=%v\n",
				pkt.Nbytes, pkt.IPAddr, pkt.Seq, pkt.Rtt)
		}
		pinger.OnFinish = func(stats *ping.Statistics) {
			info_base := fmt.Sprintf("\n--- %s ping statistics ---\n", stats.Addr)
			info_count := fmt.Sprintf("%d packets transmitted, %d packets received, %v%% packet loss\n",
				stats.PacketsSent, stats.PacketsRecv, stats.PacketLoss)
			info_time := fmt.Sprintf("round-trip min/avg/max/stddev = %v/%v/%v/%v\n",
				stats.MinRtt, stats.AvgRtt, stats.MaxRtt, stats.StdDevRtt)
			content += info_base
			content += info_count
			content += info_time
			if i == len(urls)-1 {
				//fmt.Print(content)
			}
			content += "\n"
			//fmt.Print(info_count)
			//fmt.Print(info_time)
		}

		fmt.Printf("PING %s (%s):\n", pinger.Addr(), pinger.IPAddr())
		pinger.Run()
	}
}
func download() {
	content += "=== Download testing begin ===" + "\n"
	for i, u := range mp3_urls {
		var fsize int64
		client := new(http.Client)
		client.Timeout = time.Second * 10 //设置超时时间
		start_time := time.Now()
		resp, err := client.Get(u)
		//get方法获取资源
		//resp, err := client.Get(url)
		content += "Current downloading: " + u + "\n"
		content += "Server returns status: " + resp.Status + "\n"
		content += "Server type:" + resp.Header.Get("Server") + "\n"
		content += "Connection type: " + resp.Header.Get("Connection") + "\n"
		content += "Access-Control :" + resp.Header.Get("Access-Control-Allow-Origin") + "\n"
		if err != nil {
			println(err)
			content += "Error: " + err.Error()
		}
		fsize, err = strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 32)
		if err != nil {
			println(err)
			content += "Error: " + err.Error()
		}
		println("Remote size: ", fsize)
		content += "Remote size: " + strconv.FormatInt(fsize, 10) + "\n"
		defer resp.Body.Close()

		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			println(err.Error())
			content += "Error: " + err.Error()
		}
		content += "Local size :" + strconv.Itoa(len(data)) + "\n"
		println("Local size :", len(data))
		content += "Used time: " + (time.Now().Sub(start_time).String())
		if i == len(mp3_urls)-1 {
			println(content)
		}
		content += "\n"
	}
	content += "======= Detection of network state finish ======="
	fmt.Println("End!!!!" + "\n" + content)
	fmt.Println("Test successful! Thank you for your cooperation! ")
	time.Sleep(time.Duration(2) * time.Second)
}

func getDns() {
	content += "=== Get DNS information begin ===" + "\n"
	command := "cat /etc/resolv.conf"
	par := ""
	if sysType == "windows" {
		command = "ipconfig"
		par = "/all"
	}
	str1, err := RunCommandWithErr(command, par)
	if err != nil {
		fmt.Println(err.Error())
	} else {
		content += str1 + "\n"
	}
}
func getTracert() {
	content += "=== Tracert begin ===" + "\n"
	command := "traceroute audio04.dmhmusic.com"
	par := ""
	if sysType == "windows" {
		command = "tracert"
		par = "audio04.dmhmusic.com"
	}
	str1, err := RunCommandWithErr(command, par)
	if err != nil {
		fmt.Println(err.Error())
	} else {
		content += str1 + "\n"
	}
}
func getExternalIp() string {
	resp, err := http.Get("http://members.3322.org/dyndns/getip")
	if err != nil {
		return ""
	}
	defer resp.Body.Close()
	ip, _ := ioutil.ReadAll(resp.Body)
	content += "Internet IP address: " + string(ip)
	content += "\n"
	fmt.Print(content)
	return string(ip)
}
func sendBack() {
	mailTo := []string{
		"dev@foxmail.com",
	}
	//邮件主题为"Hello"
	subject := "Testing information."
	// 邮件正文
	//body := "Hello,by gomail sent"

	err := SendMail(mailTo, subject, content)
	if err != nil {
		log.Println(err)
		fmt.Println("send fail")
		return
	}

	//fmt.Println("send successfully")
}

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
}
func runInLinux(cmd string) string {
	fmt.Println("Running Linux cmd:", cmd)
	result, err := exec.Command("/bin/sh", "-c", cmd).Output()
	if err != nil {
		fmt.Println(err.Error())
	}
	return strings.TrimSpace(string(result))
}

func runInWindows(cmd string) string {
	fmt.Println("Running Win cmd:", cmd)
	result, err := exec.Command("cmd", "/c", cmd).Output()
	if err != nil {
		fmt.Println(err.Error())
	}
	return strings.TrimSpace(string(result))
}

func RunCommand(cmd string) string {
	if runtime.GOOS == "windows" {
		return runInWindows(cmd)
	} else {
		return runInLinux(cmd)
	}
}

func RunLinuxCommand(cmd string) string {
	if runtime.GOOS == "windows" {
		return ""
	} else {
		return runInLinux(cmd)
	}
}

func runInLinuxWithErr(cmd string) (string, error) {
	fmt.Println("Running Linux cmd:" + cmd)
	result, err := exec.Command("/bin/sh", "-c", cmd).Output()
	if err != nil {
		fmt.Println(err.Error())
	}
	return strings.TrimSpace(string(result)), err
}

func runInWindowsWithErr(cmd string) (string, error) {
	fmt.Println("Running Windows cmd:" + cmd)
	result, err := exec.Command("cmd", "/c", cmd).Output()
	if err != nil {
		fmt.Println(err.Error())
	}
	return strings.TrimSpace(string(result)), err
}

func runInWindowsWithErrEncode(cmdStr string, par string) (string, error) {
	command := cmdStr
	params := []string{par}
	cmd := exec.Command(command, params...)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		fmt.Println(err)
	}
	cmd.Start()
	in := bufio.NewScanner(stdout)
	var cmdContent string
	for in.Scan() {
		cmdRe := ConvertByte2String(in.Bytes(), "GB18030")
		fmt.Println(cmdRe)
		cmdContent += cmdRe + "\n"
	}
	//cmd.Wait()
	return cmdContent, err
}

func RunCommandWithErr(cmd string, par string) (string, error) {
	if runtime.GOOS == "windows" {
		//return runInWindowsWithErr(cmd)
		return runInWindowsWithErrEncode(cmd, par)
	} else {
		return runInLinuxWithErr(cmd)
	}
}

func RunLinuxCommandWithErr(cmd string) (string, error) {
	if runtime.GOOS == "windows" {
		return "", errors.New("could not run in Windows Os")
	} else {
		return runInLinuxWithErr(cmd)
	}
}

type Charset string

const (
	UTF8    = Charset("UTF-8")
	GB18030 = Charset("GB18030")
)

func ConvertByte2String(byte []byte, charset Charset) string {
	var str string
	switch charset {
	case GB18030:
		var decodeBytes, _ = simplifiedchinese.GB18030.NewDecoder().Bytes(byte)
		str = string(decodeBytes)
	case UTF8:
		fallthrough
	default:
		str = string(byte)
	}
	return str
}

func SendMail(mailTo []string, subject string, body string) error {

	m := mail.NewMessage()
	m.SetHeader("From", "sender@lovinc.com")
	m.SetHeader("To", "receive@lovinc.com")
	m.SetHeader("Subject", subject)
	m.SetBody("text/html", strings.ReplaceAll(content, "\n", "</br>"))
	//m.Attach("/home/Alex/lolcat.jpg")

	d := mail.NewDialer("smtp.qiye.163.com", 465, "sender@lovinc.com", "senderPassword")
	d.StartTLSPolicy = mail.MandatoryStartTLS

	if err := d.DialAndSend(m); err != nil {
		panic(err)
	}
	return nil
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇