我使用的是os.File.SetReadDeadlineos.File.ReadFull的组合.但即使使用SetReadDeadline,我设定的最后期限也会被完全忽略,ReadFull块永远不会出现.为什么会这样呢?

附加信息:我向文件发出一些IOCTL,因此需要os.File.Fd()来获取文件描述符.

推荐答案

TL;DR:

在使用了os.File.Fd()之后,在文件上使用syscall.SetNonblock(fd.Fd(), true)


这是由于实施了read in golang UNIX:

func (fd *FD) Read(p []byte) (int, error) {
    if err := fd.readLock(); err != nil {
        return 0, err
    }
    defer fd.readUnlock()
    if len(p) == 0 {
        // If the caller wanted a zero byte read, return immediately
        // without trying (but after acquiring the readLock).
        // Otherwise syscall.Read returns 0, nil which looks like
        // io.EOF.
        // TODO(bradfitz): make it wait for readability? (Issue 15735)
        return 0, nil
    }
    if err := fd.pd.prepareRead(fd.isFile); err != nil {
        return 0, err
    }
    if fd.IsStream && len(p) > maxRW {
        p = p[:maxRW]
    }
    for {
        n, err := ignoringEINTRIO(syscall.Read, fd.Sysfd, p)
        if err != nil {
            n = 0
            if err == syscall.EAGAIN && fd.pd.pollable() {
                if err = fd.pd.waitRead(fd.isFile); err == nil {
                    continue
                }
            }
        }
        err = fd.eofError(n, err)
        return n, err
    }
}

如果文件设置为块模式,则前n, err := ignoringEINTRIO(syscall.Read, fd.Sysfd, p)个永久块.waitRead仅在文件以非阻塞模式打开时才执行.但我确实在非阻塞模式下打开了文件,那么发生了什么?

os.File.Fd() broke it的实施情况:

func (f *File) Fd() uintptr {
    if f == nil {
        return ^(uintptr(0))
    }

    // If we put the file descriptor into nonblocking mode,
    // then set it to blocking mode before we return it,
    // because historically we have always returned a descriptor
    // opened in blocking mode. The File will continue to work,
    // but any blocking operation will tie up a thread.
    if f.nonblock {
        f.pfd.SetBlocking()
    }

    return uintptr(f.pfd.Sysfd)
}

Fd()总是将文件设置为阻止.因此,我们必须在预期轮询读取之前undo撤消该操作.因此:

在使用了os.File.Fd()之后,在文件上使用syscall.SetNonblock(fd.Fd(), true)

Go相关问答推荐

Go编译器标志-修剪路径不完全工作

如何在另一个文件夹中使用Delve运行二进制文件?

Go在使用HTTP代理时如何处理DNS请求?

golang.org/x/oauth2 oauth2.Config.Endpoint.TokenURL mock:缺少access_token

Golang中的泛型 struct /接口列表

什么东西逃到了堆里?

包裹网.Conn导致挂起读取

如何模拟go的Elastic search SDK?

如何测试 Zerolog 记录器引发类型错误的日志(log)事件?

是否可以将 http.ServeHttp 包装在 go 中以使用 alexedwards/scs/v2 添加会话

在golang中以JSON格式获取xwwwformurlencoded请求的嵌套键值对

Golang 发送Post请求出现400错误

当填充通道的函数调用未嵌入 goroutine 时,为什么我会遇到死锁?

在密钥不存在时处理 PATCH 部分更新

如何将整数哈希细分为范围

有没有什么方法可以在不使用 if/else 的情况下在 Golang 中处理 nil 指针?

无法访问 Go 模块导入的远程存储库

为什么我不能使用来自 gocloak 中 Login() 的访问令牌在 KeyCloak 中创建新客户端?

为什么 Go 中的 maps.Keys() 将 map 类型指定为 M?

关于GO的几个问题