使用Go检查服务器端口是否可以连接

832 阅读2分钟

做一件事,无论大小,倘无恒心,是很不好的。而看一切太难,固然能使人无成,但若看得太容易,也能使事情无结果。

背景

因为负担不起每年都要在阿里云里面购买服务器的支出,于是和网络运营商申请了公网IP,在家搞了个树莓派,于是便可以省下一笔费用。但是我不是申请固定的公网IP,因此每天公网IP都会变化。于是又自己用PHP写了个DDNS,调用阿里云接口(域名是在万网申请的)动态解析新的IP。但依然会有些问题,比如网络运营商有时会把我的公网又改掉,造成我的网站无法访问,直到我自己上去看才发现,有时不够及时发现。于是便想着用程序定时去ping一下,一点ping不通就发邮件通知我。

代码

package main

import (
   "crypto/tls"
   "fmt"
   "github.com/golang-module/carbon"
   "io"
   "net"
   "os"
   "time"

   "github.com/sirupsen/logrus"
   "gopkg.in/gomail.v2"
)

func main() {
   // 记录日志
   fileName := "./logs/Info_First_" + carbon.Now().Format("Ymd") + ".log"
   logFile, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
   if err == nil {
      logrus.SetOutput(io.MultiWriter(os.Stdout, logFile))
   } else {
      logrus.SetOutput(os.Stdout)
      logrus.Error(err)
   }
   CheckServer()
}

// CheckServer ping服务器
func CheckServer() {
   // ping通后保存公网IP
   remoteAddr := ""
   // 是否发送过邮件
   isSendFlag := false
   // 失败次数
   failTimes := 0
   for {
      // 超过无响应时间则为ping不通
      timeout := time.Duration(5 * time.Second)
      conn, err := net.DialTimeout("tcp", "****:***", timeout)
      if err != nil {
         failTimes++
         // 连续超过十次判断为ping不通
         if failTimes >= 10 {
            if !isSendFlag {
               err := Send(remoteAddr + " site unreachable,please check the server")
               if err != nil {
                  logrus.Error("send email error", err)
               }
               isSendFlag = true
            }
            logrus.Error("Site unreachable, error: ", err)
            continue
         }
         // 失败一次则20s再重新ping一次
         time.Sleep(time.Duration(20 * time.Second))
         continue
      }
      // 成功则把失败次数重置
      failTimes = 0
      remoteAddr = conn.RemoteAddr().String()
      isSendFlag = false
      fmt.Println("dial success,ip: ", remoteAddr)
      time.Sleep(time.Duration(5 * time.Minute))
   }
}

func Send(content string) error {
   message := `
    <p> Hello %s,</p>
   
      <p style="text-indent:2em">%s</p>
   `

   host := "邮箱的smtp地址"
   port := 25
   userName := "你的邮箱"
   password := "邮箱smtp的密码"

   m := gomail.NewMessage()
   m.SetHeader("From", userName) // 发件人
   m.SetHeader("To", userName) // 收件人
   m.SetHeader("Subject", "Warning! Site unreachable!") // 邮件主题

   // text/html 的意思是将文件的 content-type 设置为 text/html 的形式,浏览器在获取到这种文件时会自动调用html的解析器对文件进行相应的处理。
   // 可以通过 text/html 处理文本格式进行特殊处理,如换行、缩进、加粗等等
   m.SetBody("text/html", fmt.Sprintf(message, "QiuYiEr", content))

   d := gomail.NewDialer(
      host,
      port,
      userName,
      password,
   )
   // 关闭SSL协议认证
   d.TLSConfig = &tls.Config{InsecureSkipVerify: true}

   if err := d.DialAndSend(m); err != nil {
      return err
   }
   logrus.Info("email sent")
   return nil
}

这也是我从别的博主学来的,特此注明一下:

下图为收到的邮件

image.png