根據 go 檔案,net.Conn.Write()如果無法發送給定切片中的所有位元組,該函式將回傳錯誤。
我怎么知道在這種情況下回傳的是哪種型別的錯誤?我應該檢查是否有錯誤,如果 n > 0 和 n < len(p) ?或者僅檢查 n < len(p) 是否足夠?對于 n < len(p) 是否存在不可恢復的錯誤?
例如,假設我想發送 X GB 的資料。“正確”的 Write() 回圈會是什么樣子?
如果輸出緩沖區已滿,Write() 是否只是阻塞,直到它從 p 發送了所有內容?檢查 n < len(p) 是否多余?
uj5u.com熱心網友回復:
嗯,net.Conn是一個介面。這意味著完全由實作來確定要發回哪些錯誤。TCP 連接和 UNIX 套接字連接的寫入無法完全完成的原因可能非常不同。
該net.Conn.Write簽名是完全一樣的io.Writer簽名。這意味著每個實作net.Conn也實作io.Writer. 因此,您可以使用任何現有方法,例如io.Copy或io.CopyN將資料寫入連接。
uj5u.com熱心網友回復:
該net.Conn.Write()是實作的io.Writer介面,它有關于誤差如下合同:
如果 Write 回傳 n < len(p),則它必須回傳一個非 nil 錯誤。
沒有一個正確的寫回圈。對于某些情況,了解寫入了多少資料可能很重要。但是,對于網路連接,根據本合同,以下內容應該有效:
var err error
for data, done := getNextSegment(); !done&&err==nil; data, done = getNextSegment() {
_,err=conn.Write(data)
}
要保持寫入的總位元組數:
var err error
written:=0
for data, done := getNextSegment(); !done&&err==nil; data, done = getNextSegment() {
n,err=conn.Write(data)
written =n
}
uj5u.com熱心網友回復:
我怎么知道在這種情況下回傳的是哪種型別的錯誤?我應該檢查是否有錯誤,如果 n > 0 和 n < len(p) ?
使用n < len(p)以檢測寫入提前終止的情況。在這種情況下,錯誤不是零。
對于 n < len(p) 是否存在不可恢復的錯誤?
是的。寫入某些資料后,網路連接可能會失敗。
也有可恢復的錯誤。如果由于超過寫入截止時間而導致寫入失敗,則具有新截止時間的稍后寫入可以成功。
例如,假設我想發送 X GB 的資料。“正確”的 Write() 回圈會是什么樣子?
如果您詢問如何將 a 寫入[]byte連接,則在大多數情況下不需要回圈。Write 呼叫會阻塞,直到寫入資料或發生錯誤。使用此代碼:
_, err := c.Write(p)
如果您詢問如何將 io.Reader 復制到網路連接,請使用_, err := io.Copy(conn, r).
寫不同于讀。Read 可以在填充緩沖區之前回傳。
如果輸出緩沖區已滿,Write() 是否只是阻塞,直到它從 p 發送了所有內容?
寫入阻塞,直到所有資料發送或寫入失敗并出現錯誤(超過截止日期、網路故障、其他 goroutine 中的網路連接關閉,...)。
uj5u.com熱心網友回復:
因此,我深入研究了 Go 源代碼本身。我跟蹤了對名為src/internal/poll/fd_unix.go.
// Write implements io.Writer.
func (fd *FD) Write(p []byte) (int, error) {
if err := fd.writeLock(); err != nil {
return 0, err
}
defer fd.writeUnlock()
if err := fd.pd.prepareWrite(fd.isFile); err != nil {
return 0, err
}
var nn int
for {
max := len(p)
if fd.IsStream && max-nn > maxRW {
max = nn maxRW
}
n, err := ignoringEINTRIO(syscall.Write, fd.Sysfd, p[nn:max])
if n > 0 {
nn = n
}
if nn == len(p) {
return nn, err
}
if err == syscall.EAGAIN && fd.pd.pollable() {
if err = fd.pd.waitWrite(fd.isFile); err == nil {
continue
}
}
if err != nil {
return nn, err
}
if n == 0 {
return nn, io.ErrUnexpectedEOF
}
}
}
這似乎已經處理了重傳。所以,Write() 實際上保證要么發送所有內容,要么發生致命錯誤,這是不可恢復的。
在我看來,除了用于日志記錄之外,根本沒有必要關心 n 的值。如果發生錯誤,那么嚴重到沒有理由嘗試重新傳輸剩余的 len(p)-n 位元組。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/352561.html
標籤:走
