4 回答

TA貢獻(xiàn)1818條經(jīng)驗(yàn) 獲得超8個(gè)贊
嗯,net.Conn
是一個(gè)界面。這意味著完全取決于實(shí)現(xiàn)來確定要發(fā)送回哪些錯(cuò)誤。TCP 連接和 UNIX 套接字連接可能有非常不同的原因?qū)е聼o法完全完成寫入。
簽名與net.Conn.Write
簽名完全相同io.Writer
。這意味著每個(gè)實(shí)現(xiàn)net.Conn
也實(shí)現(xiàn)io.Writer
. 因此,您可以使用任何現(xiàn)有方法,例如io.Copy
或io.CopyN
將數(shù)據(jù)寫入連接。

TA貢獻(xiàn)1784條經(jīng)驗(yàn) 獲得超2個(gè)贊
在這種情況下,我如何知道返回了哪種類型的錯(cuò)誤?我應(yīng)該檢查是否有錯(cuò)誤,如果 n > 0 和 n < len(p) ?
用于n < len(p)
檢測(cè)寫入提前停止的情況。在這種情況下,錯(cuò)誤不是零。
是否存在 n < len(p) 的不可恢復(fù)錯(cuò)誤?
是的。寫入某些數(shù)據(jù)后,網(wǎng)絡(luò)連接可能會(huì)失敗。
也有可恢復(fù)的錯(cuò)誤。如果由于超過了寫入期限而導(dǎo)致寫入失敗,則具有新期限的稍后寫入可以成功。
例如,假設(shè)我想發(fā)送 X GB 的數(shù)據(jù)?!罢_”的 Write() 循環(huán)會(huì)是什么樣子?
如果您詢問如何將 a 寫入[]byte
連接,則在大多數(shù)情況下不需要循環(huán)。在寫入數(shù)據(jù)或發(fā)生錯(cuò)誤之前,Write 調(diào)用會(huì)阻塞。使用此代碼:
_, err := c.Write(p)
如果您詢問如何將 io.Reader 復(fù)制到網(wǎng)絡(luò)連接,請(qǐng)使用_, err := io.Copy(conn, r)
.
寫不同于讀。讀取可以在填充緩沖區(qū)之前返回。
如果輸出緩沖區(qū)已滿,Write() 會(huì)阻塞直到它從 p 發(fā)送所有內(nèi)容?
寫入阻塞,直到所有數(shù)據(jù)都發(fā)送完畢或?qū)懭胧〔⒊霈F(xiàn)錯(cuò)誤(超過最后期限,網(wǎng)絡(luò)故障,網(wǎng)絡(luò)連接在其他 goroutine 中關(guān)閉,...)。

TA貢獻(xiàn)1835條經(jīng)驗(yàn) 獲得超7個(gè)贊
因此,我深入研究了 Go 源代碼本身。我跟蹤了對(duì)名為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
}
}
}
這似乎已經(jīng)處理了重傳。因此,Write() 實(shí)際上確實(shí)保證了所有內(nèi)容都已發(fā)送,或者發(fā)生了無法恢復(fù)的致命錯(cuò)誤。
在我看來,除了記錄目的之外,根本不需要關(guān)心 n 的值。如果曾經(jīng)發(fā)生錯(cuò)誤,那么它已經(jīng)足夠嚴(yán)重以至于沒有理由嘗試重新傳輸剩余的 len(p)-n 個(gè)字節(jié)。

TA貢獻(xiàn)1828條經(jīng)驗(yàn) 獲得超13個(gè)贊
這net.Conn.Write()是為了實(shí)現(xiàn)io.Writer接口,該接口具有以下關(guān)于錯(cuò)誤的約定:
如果返回 n < len(p),則寫入必須返回非零錯(cuò)誤。
沒有一個(gè)正確的寫循環(huán)。對(duì)于某些情況,了解寫入了多少數(shù)據(jù)可能很重要。但是,對(duì)于網(wǎng)絡(luò)連接,基于此合同,以下內(nèi)容應(yīng)該有效:
var err error
for data, done := getNextSegment(); !done&&err==nil; data, done = getNextSegment() {
_,err=conn.Write(data)
}
要保持寫入的字節(jié)總數(shù):
var err error
written:=0
for data, done := getNextSegment(); !done&&err==nil; data, done = getNextSegment() {
n,err=conn.Write(data)
written+=n
}
- 4 回答
- 0 關(guān)注
- 273 瀏覽
添加回答
舉報(bào)