英文:
Handling errors following net packet read timeout
问题
我正在使用conn.SetReadDeadline
方法为conn
设置读取超时时间。当conn.Read
等待的时间超过指定的时间时,它将返回并返回一个类型为*net.OpError
的错误。这个错误是在包装所有非io.EOF
错误之后由net
包返回的。
我可以在包装之前使用Unwrap()
获取错误。超时错误是*poll.DeadlineExceededError
类型的错误。我在我的代码中使用类似这样的语句来精确处理超时错误。
import "internal/poll"
_, err = conn.Read(p)
if err != nil {
if pe, ok := err.(*net.OpError); ok {
err = pe.Unwrap()
if timeout, ok := err.(*poll.DeadlineExceededError); ok {
log.Error(fmt.Sprintf("%T, %s", timeout, timeout))
}
}
return
}
在运行程序时,我收到了一个use of internal package internal/poll not allowed
的错误。编译器告诉我不能使用内部包。
我通过谷歌搜索找到了一个解决方案,即删除internal
文件夹,这是最终解决方案吗?是否会有更好的解决方案?
英文:
I am using the conn.SetReadDeadline
method to set the read timeout for conn
, When conn.Read
waits for more than the specified time, it will return and return an error of type *net.OpError
. This error is returned by the net
package after wrapping all non-io.EOF
errors.
I can get the error before wrapping with Unwrap()
. A timeout error is an error of type *poll.DeadlineExceededError
. I use statements like this in my code to handle timeout errors precisely.
import "internal/poll"
_, err = conn.Read(p)
if err != nil {
if pe, ok := err.(*net.OpError); ok {
err = pe.Unwrap()
if timeout, ok := err.(*poll.DeadlineExceededError); ok {
log.Error(fmt.Sprintf("%T, %s", timeout, timeout))
}
}
return
}
I received an use of internal package internal/poll not allowed
error while running the program. The compiler tells me that internal packages cannot be used.
I googled and found a solution to delete the internal
folder, is this the final solution? Will there be a better solution?
答案1
得分: 3
os
包将该错误导出为os.ErrDeadlineExceeded
(请查看源代码)。你可以尝试使用以下代码:
if errors.Is(err, os.ErrDeadlineExceeded) {
log.Error("Timeout error")
}
[编辑] 实际上,在阅读了@Brit的评论后,这是检查该错误的文档化方法。请参阅Conn.SetDeadline()
的文档:
> 如果超过截止时间,对Read或Write或其他I/O方法的调用将返回一个包装了os.ErrDeadlineExceeded的错误。可以使用errors.Is(err, os.ErrDeadlineExceeded)进行测试。
另一个指示错误是“超时”错误的方法是,如果它具有一个Timeout() bool
方法,在调用时返回true
。
这是net.Error
接口的一部分(尽管该接口有一个额外的方法,被记录为已弃用),并由net.OpError
类型(以及内部的poll.DeadlineExceededError
类型)实现。
有几个函数(例如net.OpError.IsTimeout()
、os.SyscallError.IsTimeout()
和公共函数os.IsTimeout()
)通过直接将错误值转换为timeout
接口来实现超时检查。
如果你想处理可以相互包装的错误,你可能希望使用errors.As(...)
来实现自己的isTimeout()
检查:
// isTimeout:使用errors.As()来解包错误并检查子错误是否为超时错误
func isTimeout(err error) bool {
var terr interface{ Timeout() bool }
return errors.As(err, &terr) && terr.Timeout()
}
https://go.dev/play/p/OhhKY3XsGjZ
请注意:
上面的isTimeout()
函数与errors.Is(err, os.ErrDeadlineExceeded)
调用之间的区别在于,后者将尝试精确匹配ErrDeadlineExceeded
(这主要是通过在某些类似文件或连接的对象上设置SetDeadline()
触发的),而后者可能对试图以其他原因宣告“我是超时错误”的错误返回true(例如:HTTP的“408 Request timeout”响应)
*注意:*上面的所有链接都指向go 1.18.3。根据你使用的go版本,你可能需要调整上面的一些代码(例如:os.ErrDeadlineExceeded
是在go1.15中添加的)
英文:
The os
package exports that error as os.ErrDeadlineExceeded
(check the source code). You can try :
if errors.Is(err, os.ErrDeadlineExceeded) {
log.Error("Timeout error")
}
[edit] actually, after reading @Brit's comment, this is the documented way to check for that error. See the doc for Conn.SetDeadline()
:
> If the deadline is exceeded a call to Read or Write or to other
I/O methods will return an error that wraps os.ErrDeadlineExceeded.
This can be tested using errors.Is(err, os.ErrDeadlineExceeded).
Another indication that an error is a "timeout" error is if it has a Timeout() bool
method, which returns true
when called.
This is part of the net.Error
interface (although this interface has an extra method, which is documented as deprecated), and implemented by the net.OpError
type (and also by the internal poll.DeadlineExceededError
type).
There are several functions (net.OpError.IsTimeout()
, os.SyscallError.IsTimeout()
and the public function os.IsTimeout()
for example) that implement a timeout checking by directly casting the error value to a timeout
interface.
If you want to deal with errors that can be wrapped one into another, you may want to implement your own isTimeout()
check using errors.As(...)
:
// isTimeout : use errors.As() to unwrap errors and check if a sub error is a Timeout error
func isTimeout(err error) bool {
var terr interface{ Timeout() bool }
return errors.As(err, &terr) && terr.Timeout()
}
https://go.dev/play/p/OhhKY3XsGjZ
note that :
the difference between the isTimeout()
function above and the errors.Is(err, os.ErrDeadlineExceeded)
call is that the latter will try to match exacly an ErrDeadlineExceeded
(which is mostly triggered by setting SetDeadline()
on some file-or-conn-like object), while the latter one may return true for errors that try to advertise "I'm a timeout error" for other reasons (e.g : an HTTP "408 Request timeout" response)
note : all links above refer to go 1.18.3 . Depending on the version of go you are using, you may have to adapt some of the code above (for example : the os.ErrDeadlineExceeded
was added in go1.15 )
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论