【问题标题】:How to explicitly send an EOF to an io.ReadCloser in golang?go - 如何在golang中将EOF显式发送到io.ReadCloser?
【发布时间】:2021-08-24 03:22:22
【问题描述】:

希望您收到这条消息时身体健康。

所以在我正在研究的 golang 程序中存在这个错误,代码库中的这种阻塞方法 stdCopy.StdCopy() 会导致一切挂起。出现这个问题是因为 Docker 不断地向 Stdcopy 阻塞方法发送信息,而阻塞方法只有在发送 EOF 时才能停止运行。 StdCopy 接受 ReadCloser 类型参数,这是阻塞方法从 Docker 读取信息的方式。在程序进入阻塞方法之前,也会使用 Goroutines。换句话说,StdCopy 阻塞方法在一个新线程中运行,而主线程与它并行运行。但是,阻塞方法现在阻塞了新线程,并不能解决问题。

我试图防止这个问题是在主线程中显式关闭这个 ReadCloser,然后发送一个 EOF 到持有 StdCopy 阻塞方法的新线程,以通过超时错误强制停止它。这应该阻止整个程序挂起,因为阻塞方法是它挂起的原因。我通过存储我打开的每个 ReadCloser 的映射来做到这一点,然后以特定方法手动将它们全部关闭,该方法旨在在我们的程序停止时运行。我不确定关闭 ReadCloser 接口是否会自动发送 EOF(我检查了 golang 文档,但找不到任何信息:https://golang.org/pkg/io/#ReadCloser)。

我决定要明确地向 ReadCloser 发送 EOF 以防万一。但是,我该怎么做呢?我正在考虑使用我的通道知识并通过通道将 io.EOF 传递到运行阻塞方法的 go-routine 中。但是 io.ReadCloser 不是通道类型,所以我不能这样做。

关闭 io.ReadCloser 会自动发送 EOF 吗?如果没有,您将如何将 EOF 发送到 io.ReadCloser 以便阻止方法停止运行?

如果我的解释中有任何不合理之处,请告诉我,您希望我澄清一下。由于我对 golang 还比较陌生,因此在您认为我有错误的地方也可以随时纠正我。

非常感谢您抽出宝贵时间,如有任何想法请告诉我!

----- 编辑-----

以下是我迄今为止编写的一些代码,以便更好地理解:

        //Closing all of the ReadClosers opened to prevent blocking
        for k := range streamer.inputReadClosers {
            (*k).Close()
            //(*k) <- io.EOF //does not work since io.ReadCloser is not of channel type
        }

所以在某些情况下,streamer 只是一个结构,它包含一个属性调用 inputReadClosers,它是所有打开的 ReadClosers 的指针映射。然后我显式关闭 ReadCloser,然后目标是手动向该 ReadCloser 发送 EOF。

一些关于 ReadCloser 是如何初始化的信息:

所以我有一个文件,该文件的方法具有以下方法标头func (streamer *LogStreamer) StartStreamingFromDockerLogs(input io.ReadCloser) error。当我检查 StartStreamingFromDockerLogs(...) 在其他文件中使用的实例时,我发现传递了一个 readcloser 变量,并且 readcloser 变量以下列方式初始化:readCloser, err := dockerManager.GetContainerLogs(.....three parameters here…..)

【问题讨论】:

  • 所以 io.ReadCloser 是一个包含 Reader 接口和 Closer 接口的接口。 Reader 和 Closer 接口分别持有 Read 和 Close 方法。我在我的 C 系统编程课程中了解了管道,我认为规则是,如果在管道的写入端关闭并且已从管道读取所有数据时,读取调用返回 0。但我认为我不能在这里做到这一点,因为 io.ReadCloser 至少从我对文档的理解来看不是管道:golang.org/pkg/io/#ReadCloser
  • @Penelope Stevens 很抱歉没有澄清我上面的评论是针对哪个用户的(它是针对 Cerise 的,感谢 Cerise 的评论!)。但是,感谢@Penelope Stevens 关于如何确定具体类型的评论!我尝试了您在上面发送的 fmt.Printf() 语句,并得到以下信息:my io.ReadCloser is a *http.bodyEOFSignal
  • @Penelope Stevens 我在上面的问题中添加了一些代码,以尝试更好地理解我的问题。你是对的,我认识到我的问题看起来像 XY 问题。感谢您指出这一点,让我试着澄清一下,以便我试图理解问题,而不是仅仅找到问题的解决方案。
  • @Penelope Stevens 所以我有一个文件,该文件有一个方法,其方法标题为func (streamer *LogStreamer) StartStreamingFromDockerLogs(input io.ReadCloser) error。当我检查在其他文件中使用StartStreamingFromDockerLogs(...) 的实例时,我发现传递了一个 readcloser 变量,并且 readcloser 变量以下列方式初始化:readCloser, err := dockerManager.GetContainerLogs(.....three parameters here…..)。也许GetContainerLogs(....) 引起了问题?我会调查并随时通知您。

标签: docker go eof blocking reader


【解决方案1】:

这实际上是一个评论,而不是一个答案,只是它太大而不能成为评论(并且需要一些格式)。

这里有一些根本性的不匹配,使得这个问题无法解决:

  • 首先,文件结尾,例如由io.EOF 错误表示,不是您可以通过任何类型的数据流发送的东西。这是一个适用于流的条件,在这种情况下,无法接收到更多数据(至少目前,该条件可能会在未来清除)。

  • 其次,io.ReadCloser 就是实现ReadClose 方法的任何东西(具有io.Readerio.Closer)。你不能“发送”一个 EOF 这个。 EOF 发生Read 函数返回io.EOF 错误,作为其两个返回值之一。如果某个类型 T 实现了io.ReadCloser,并且您将 T 类型的值传递给某个函数 f,然后 f em> 调用它的Read 方法,这会返回io.EOF 作为它的错误条件,那么这个T 的阅读器产生了一个EOF 条件。

作为Penelope Stevens said in a comment,如果我们知道碰巧实现io.ReadCloser的实际具体类型Tc那么我们可能是能够找到某种方法来说服 Tc 的读者返回 io.EOF 错误。这又需要检查 Tc 的源代码或文档。例如:

type Foo struct {
    // unexported fields
    TemporaryEOF bool
}
...
func (Foo *f) Read(p []byte) (n int, err error) {
    // if we're supposed to assert a temporary EOF now, do so
    if f->temporaryEOF {
        return 0, io.EOF
    }
    // rest of code here
}
// implement io.Closer() here too

这告诉我们,实际上实现了io.ReadCloserFoo 对象可以通过将其TemporaryEOF 数据字段设置为true 来强制呈现EOF 一段时间。

这不适用于实现io.ReadCloser 的其他项目,因为它们没有TemporaryEOF 数据字段。这种在程序运行期间强制EOF一段时间的特殊方法是Foo对象特有的。 这正是我们无法解决的问题,因为我们没有正确的信息:导致 EOF 条件发生的代码是 Tc 的 Read 函数中的代码sub>. 除非您向我们展示该代码(或让我们找到该代码的东西),否则我们无法告诉您如何使其产生 EOF 条件。

【讨论】:

  • 啊,谢谢你解开我的误会!我认为当时我的 EOF 设计可能不是最好的,我可能想研究另一种策略。但是,我会尝试改进我的问题,以使所有愿意帮助我解决我的问题的人更容易。我已经用一些代码更新了上面的帖子,但我会尝试找到 io.ReadCloser 的实现(特别是 Read 函数)并为您发布该代码。我很抱歉没有说清楚,谢谢你的耐心:)
猜你喜欢
  • 1970-01-01
  • 2020-08-22
  • 2016-04-23
  • 1970-01-01
  • 2017-10-20
  • 2013-07-20
  • 2013-06-19
  • 2018-12-16
  • 2018-04-28
相关资源
最近更新 更多