php小編子墨在這篇文章中將為您解答關於Golang中使用os.File.Fd()時SetDeadline/SetReadDeadline/SetWriteDeadline對檔案不起作用的問題。在Golang中,這些方法是用來設定檔案的截止時間,但是有時候可能會出現無效的情況。接下來,我們將探討可能的原因,並提供解決方案來確保這些方法正常運作。
我使用 os.File.SetReadDeadline
和 os.File.ReadFull
的組合。但即使使用 SetReadDeadline
,我設定的截止日期也被完全忽略,並且 ReadFull
永遠阻塞。這是為什麼?
其他資訊:我向檔案觸發了一些 IOCTLS,因此需要 os.File.Fd() 來取得檔案描述子。
tl;博士:
使用 os.file.fd()
後,在檔案上使用 syscall.setnonblock(fd.fd(), true)
這是由於 read
在 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()
的實作 破壞了它:
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()
始終將檔案設定為阻塞。因此,我們必須在等待輪詢讀取之前撤銷該操作。因此:
使用 os.file.fd()
後,在檔案上使用 syscall.setnonblock(fd.fd(), true)
以上是GOLANG:為什麼在使用 os.File.Fd() 時 SetDeadline/SetReadDeadline/SetWriteDeadline 對檔案不起作用?的詳細內容。更多資訊請關注PHP中文網其他相關文章!