jjzjj

go - golang 中的 smtp 问题( panic ,信号 SIGSEGV : segmentation violation)

coder 2024-07-05 原文

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

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
}

下一步 - 我的函数从字面上检查电子邮件是否存在(顺便说一句,这个函数来自小型库 github.com/badoux/checkmail 但如果我只使用这个函数,我将它复制粘贴到我的代码中以记录错误、变量等。 ):

func validateHost(email string) error {
    _, host := split(email)
    mx, err := net.LookupMX(host)
    if err != nil {
        fmt.Printf("Error, UnresolvableHost! %s", err)
    }

    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)
    }

    t := time.AfterFunc(forceDisconnectAfter, func() { client.Close() })
    defer t.Stop()

    // t := NewTimer(10, func() { client.Close() })
    // defer t.Stop()

    err = client.Hello("checkmail.me")
    //err = client.Hello("gmail.com")
    //  fmt.Println(client)
    if err != nil {
        //log.Fatalln(err)
        fmt.Printf("client.Hello SmtpError! %s \n", err)
    }

    err = client.Mail("lansome-cowboy@gmail.com")
    if err != nil {
        fmt.Printf("client.MailSmtpError! %s \n", err)
    }
    err = client.Rcpt(email)
    if err != nil {
        fmt.Printf("client.Rcpt SmtpError! %s \n", err)
    }
    return nil
}

而且我还制作了支持功能,该功能会中断检查服务器响应是否太长:

   // 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
}

以及上述功能需要的其他支持功能:

    func split(email string) (account, host string) {
    i := strings.LastIndexByte(email, '@')
    account = email[:i]
    host = email[i+1:]
    return
}

const forceDisconnectAfter = time.Second * 10

进入函数的 slice 的例子是

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 下一个:

    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

我真的无法理解如何处理这种 panic 。另外,仅供引用,应用程序在检查了大约 3-5 个 slice 后崩溃,几个小时前检查了 10 个邮件 slice ,然后崩溃了。

而且,重要的是,过去 1-2 周一切都很好,没有错误/ panic 。我给函数提供了 20-50-100-150 封电子邮件(1 封邮件接近 15 封电子邮件)并且没有错误。

如有任何帮助,我们将不胜感激!

最佳答案

您没有进行正确的错误处理。这可能是您遇到问题的原因。特别是,您会从堆栈跟踪中注意到,您在标准库的 smtp.go 文件的第 76 行遇到了 panic 。这一行写着:

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 连接失败,您将尝试关闭无效连接,这很可能会导致观察到的行为。

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

  1. 不仅要打印错误,还要处理它们。这可能只是意味着归还它们:

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

    针对您的每一个错误执行此操作。

  2. 只有在知道连接有效后才调用 client.Close()!

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

关于go - golang 中的 smtp 问题( panic ,信号 SIGSEGV : segmentation violation),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50292325/

有关go - golang 中的 smtp 问题( panic ,信号 SIGSEGV : segmentation violation)的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  3. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  4. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  5. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

  6. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

  7. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  8. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  9. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  10. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

随机推荐