golang中smtp存在问题(死机、信号SIGSEGV:分段冲突)

golang中smtp存在问题(死机、信号SIGSEGV:分段冲突),go,smtp,Go,Smtp,我有一个小应用程序,可以验证邮件服务器上是否存在电子邮件。我知道我的实现不会给出100%的结果,但让它去吧。 所以,我得到了func,它获取电子邮件片段并检查该片段中的每封电子邮件: func CheckMails(mails []string) []string { var existingMails []string fmt.Printf("!!!!!!!!!!!!!!STARTING!!!!!!!!!!!! %s \n\n\n", mails[1]) for i :

我有一个小应用程序,可以验证邮件服务器上是否存在电子邮件。我知道我的实现不会给出100%的结果,但让它去吧。 所以,我得到了func,它获取电子邮件片段并检查该片段中的每封电子邮件:

func CheckMails(mails []string) []string {
    var existingMails []string
    fmt.Printf("!!!!!!!!!!!!!!STARTING!!!!!!!!!!!! %s \n\n\n", mails[1])
    for i := 0; i < len(mails); i++ {
        err := validateHost(mails[i])
        if err != nil {
            fmt.Printf("Error validating host. %s", err)
        }
        smtpErr, ok := err.(checkmail.SmtpError)
        if ok {
            fmt.Printf("Code: %s, Msg: %s", smtpErr.Code(), smtpErr)
            if smtpErr.Code() == "dia" {
                break
            }
        } else {
            fmt.Println("Email exists")
            existingMails = append(existingMails, mails[i])
        }
    }
    fmt.Printf("!!!!!!!!!!!!!!ENDING!!!!!!!!!!!! %s \n\n\n", mails[1])
    return existingMails
}
此外,我还提供了支持功能,可以中断检查服务器的响应是否过长:

   // CheckMailsWithExpectedInterval want to get expectected number of seconds which you are ready to wait while
// the mail trys to be validated (this time is for ONE mail, slice could have a lot of mails to check)
// and slice of mails which should be validated
func CheckMailsWithExpectedInterval(expectedSec int, mails []string) (ok bool, existingMails []string) {
    done := make(chan struct{})
    t1 := time.Now()
    var eMails []string
    go func() {
        eMails = CheckMails(mails)
        close(done)
    }()

    select {
    case <-done:
        if len(eMails) > 1 {
            ok = false
        } else {
            ok = true
            existingMails = eMails
        }
    case <-time.After(time.Duration(expectedSec) * time.Second):
    }

    fmt.Printf("\nTime since:")
    fmt.Println(time.Since(t1))
    return ok, existingMails
}
进入函数的切片示例如下

email1 := []string{
        "andreasId@fromatob.com",
        "Andreas.Wolff@fromatob.com",
        "AndreasWolff@fromatob.com",
        "Wolff.Andreas@fromatob.com",
        "WolffAndreas@fromatob.com",
        "Andreas@fromatob.com,Wolff@fromatob.com",
        "A.Wolff@fromatob.com",
        "AWolff@fromatob.com",
        "Andreas.W@fromatob.com",
        "AndreasW@fromatob.com",
        "Wolff.A@fromatob.com",
        "WolffA@fromatob.com",
        "W.Andreas@fromatob.com",
        "WAndreas@fromatob.com",
    }
我还有一个问题。有时我的应用程序会出现恐慌,下一步:

    panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x84fefa]
goroutine 260 [running]:
net/smtp.(*Client).Close(0x0, 0x0, 0x0)
    /usr/lib/go-1.10/src/net/smtp/smtp.go:76 +0x2a
panic(0x90a360, 0xb94ae0)
    /usr/lib/go-1.10/src/runtime/panic.go:502 +0x24a
net/smtp.(*Client).Hello(0x0, 0x97d912, 0x9, 0x0, 0x0)
    /usr/lib/go-1.10/src/net/smtp/smtp.go:100 +0x78
magictool/mailchecker.validateHost(0xc4204c7020, 0x23, 0x0, 0x0)
    /home/username/go/src/magictool/mailchecker/mailchecker.go:115 +0x749
magictool/mailchecker.CheckMails(0xc4201c0000, 0xf, 0xf, 0x0, 0x0, 0x0)
    /home/username/go/src/magictool/mailchecker/mailchecker.go:20 +0x1d1
magictool/mailchecker.CheckMailsWithExpectedInterval.func1(0xc4201c0000, 0xf, 0xf, 0xc42038f5c0, 0xc4203b7ec0)
    /home/username/go/src/magictool/mailchecker/mailchecker.go:49 +0x3f
created by magictool/mailchecker.CheckMailsWithExpectedInterval
    /home/username/go/src/magictool/mailchecker/mailchecker.go:48 +0x12c
我真的不明白如何处理这种恐慌。另外,仅供参考,应用程序在检查了3-5个片段后崩溃,几个小时前检查了10个邮件片段,然后崩溃

而且,重要的是,过去1-2周一切正常,没有错误/恐慌。我给函数20-50-100-150条电子邮件(1条接近15条电子邮件),没有错误


任何帮助都将不胜感激

您没有正确处理错误。这可能是造成您的问题的原因。特别是,您会从堆栈跟踪中注意到,在标准库的
smtp.go
文件的第76行出现了恐慌。该行内容如下:

return c.Text.Close()
因此,您似乎试图关闭一个无效的连接

当我们阅读您的代码时,这是很直观的:

client, err := smtp.Dial(fmt.Sprintf("%s:%d", mx[0].Host, 25))
//  fmt.Println(client)
defer client.Close()
if err != nil {
    //fmt.Println(client)
    //log.Fatalln(err)
    fmt.Printf("SmtpError! %s \n", err)
}
您甚至在知道客户端连接是否有效之前就调用了
defer client.Close()
。这意味着,如果SMTP连接失败,您将尝试关闭无效连接,这很可能导致观察到的行为

要更正此问题,必须进行两项更改

  • 不仅仅是打印错误,还要处理它们。这可能只是意味着退回它们:

    client, err := smtp.Dial(fmt.Sprintf("%s:%d", mx[0].Host, 25))
    defer client.Close()
    if err != nil {
        return err
    }
    
    对你的每一个错误都这样做

  • 只有在你知道你有一个有效的连接后才调用
    client.Close()

    client, err := smtp.Dial(fmt.Sprintf("%s:%d", mx[0].Host, 25))
    if err != nil {
        return err
    }
    defer client.Close()
    

  • 您没有进行正确的错误处理。这可能是造成您的问题的原因。特别是,您会从堆栈跟踪中注意到,在标准库的
    smtp.go
    文件的第76行出现了恐慌。该行内容如下:

    return c.Text.Close()
    
    因此,您似乎试图关闭一个无效的连接

    当我们阅读您的代码时,这是很直观的:

    client, err := smtp.Dial(fmt.Sprintf("%s:%d", mx[0].Host, 25))
    //  fmt.Println(client)
    defer client.Close()
    if err != nil {
        //fmt.Println(client)
        //log.Fatalln(err)
        fmt.Printf("SmtpError! %s \n", err)
    }
    
    您甚至在知道客户端连接是否有效之前就调用了
    defer client.Close()
    。这意味着,如果SMTP连接失败,您将尝试关闭无效连接,这很可能导致观察到的行为

    要更正此问题,必须进行两项更改

  • 不仅仅是打印错误,还要处理它们。这可能只是意味着退回它们:

    client, err := smtp.Dial(fmt.Sprintf("%s:%d", mx[0].Host, 25))
    defer client.Close()
    if err != nil {
        return err
    }
    
    对你的每一个错误都这样做

  • 只有在你知道你有一个有效的连接后才调用
    client.Close()

    client, err := smtp.Dial(fmt.Sprintf("%s:%d", mx[0].Host, 25))
    if err != nil {
        return err
    }
    defer client.Close()
    

  • 谢谢你的快速回复!我会尝试并说出结果!这很有帮助!非常感谢@谢谢你的快速回复!我会尝试并说出结果!这很有帮助!非常感谢@脆弱的