dongniaoli1822 2014-01-04 21:25
浏览 53
已采纳

进行错误处理,类型断言和网络软件包

I'm learning go and trying to understand how to get more detailed error information out of the generic error type. The example I'll use is from the net package, specifically the DialTimeout function.

The signature is

func DialTimeout(network, address string, timeout time.Duration) (Conn, error)

The error type only defines an Error() string function. If I want to find out exactly why DialTimeout failed, how can I get that information? I found out that I can use type assertion to get the net.Error specific error:

con, err := net.DialTimeout("tcp", net.JoinHostPort(address, "22"),
    time.Duration(5) * time.Second)
if err != nil {
    netErr, ok := err.(net.Error)
    if ok && netErr.Timeout() {
        // ...
    } 
} 

but that only tells me whether or not I had a timeout. For example, say I wanted to differentiate between a refused connection and no route to host. How can I do that?

Maybe DialTimeout is too high-level to give me that kind of detail, but even looking at syscall.Connect, I don't see how to get the specific error. It just says it returns the generic error type. Compare that to the Posix connect, which will let me know why it failed with the various return codes.

My general question is: how am I supposed to pull out error details from the generic error type if the golang docs don't tell me what type of errors may be returned?

  • 写回答

1条回答 默认 最新

  • douza9835 2014-01-04 22:06
    关注

    Most networking operations return a *OpError which holds detailed information about the error and implements the net.Error interface. So for most use cases it is sufficient to use net.Error as you already did.

    But for your case you'd want to assert the returned error to be *net.OpError and use the internal error:

    if err != nil {
        if oerr, ok := err.(*OpError); ok {
            // Do something with oerr.Err
        }
    }
    

    As soon as you're doing this you are in the land of platform dependency as syscalls under Linux can fail differently to those under Windows. For Linux you'd do something like this:

    if oerr.Err == syscall.ECONNREFUSED {
        // Connection was refused :(
    }
    

    The syscall package contains the important error constants for your platform. Unfortunately the golang website only shows the syscall package for Linux amd64. See here for ECONNREFUSED.

    Finding out types

    The next time you're wondering what is actually returned by some function and you can't make heads and tails of it, try using the %#v format specified in fmt.Printf (and friends):

     fmt.Printf("%#v
    ", err)
     // &net.OpError{Op:"dial", Net:"tcp", Addr:(*net.TCPAddr)(0xc20006d390), Err:0x6f}
    

    It will print detailed type information and is generally quite helpful.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 怎么在stm32门禁成品上增加记录功能
  • ¥15 Source insight编写代码后使用CCS5.2版本import之后,代码跳到注释行里面
  • ¥50 NT4.0系统 STOP:0X0000007B
  • ¥15 想问一下stata17中这段代码哪里有问题呀
  • ¥15 flink cdc无法实时同步mysql数据
  • ¥100 有人会搭建GPT-J-6B框架吗?有偿
  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 解riccati方程组