網絡通訊中,爲了防止長時間無響應的狀況,常常會用到網絡鏈接超時、讀寫超時的設置。golang
本文結合例子簡介golang的鏈接超時和讀寫超時設置。網絡
func DialTimeout(network, address string, timeout time.Duration) (Conn, error)
第三個參數timeout
能夠用來設置鏈接超時設置。
若是超過timeout
的指定的時間,鏈接沒有完成,會返回超時錯誤。tcp
在Conn
定義中,包括讀寫的超時時間設置。函數
type Conn interface { // SetDeadline sets the read and write deadlines associated // with the connection. It is equivalent to calling both // SetReadDeadline and SetWriteDeadline. // ... ... SetDeadline(t time.Time) error // SetReadDeadline sets the deadline for future Read calls // and any currently-blocked Read call. // A zero value for t means Read will not time out. SetReadDeadline(t time.Time) error // SetWriteDeadline sets the deadline for future Write calls // and any currently-blocked Write call. // Even if write times out, it may return n > 0, indicating that // some of the data was successfully written. // A zero value for t means Write will not time out. SetWriteDeadline(t time.Time) error }
經過上面的函數說明,能夠得知,這裏的參數t
是一個將來的時間點,因此每次讀或寫以前,都要調用SetXXX
從新設置超時時間,測試
若是隻設置一次,就會出現老是超時的問題。ui
server端監聽鏈接,若是收到鏈接請求,就是建立一個goroutine負責這個鏈接的數據收發。code
爲了測試超時,咱們在寫操做以前,sleep 3s。server
package main import ( "net" "log" "time" ) func main() { addr := "0.0.0.0:8080" tcpAddr, err := net.ResolveTCPAddr("tcp",addr) if err != nil { log.Fatalf("net.ResovleTCPAddr fail:%s", addr) } listener, err := net.ListenTCP("tcp", tcpAddr) if err != nil { log.Fatalf("listen %s fail: %s", addr, err) } else { log.Println("listening", addr) } for { conn, err := listener.Accept() if err != nil { log.Println("listener.Accept error:", err) continue } go handleConnection(conn) } } func handleConnection(conn net.Conn) { defer conn.Close() var buffer []byte = []byte("You are welcome. I'm server.") for { time.Sleep(3*time.Second)// sleep 3s n, err := conn.Write(buffer) if err != nil { log.Println("Write error:", err) break } log.Println("send:", n) } log.Println("connetion end") }
client創建鏈接時,使用的超時時間是3s。ci
建立鏈接成功後,設置鏈接的讀超時。
每次讀以前,都從新設置超時時間。string
package main import ( "log" "net" "os" "time" ) func main() { connTimeout := 3*time.Second conn, err := net.DialTimeout("tcp", "127.0.0.1:8080", connTimeout) // 3s timeout if err != nil { log.Println("dial failed:", err) os.Exit(1) } defer conn.Close() readTimeout := 2*time.Second buffer := make([]byte, 512) for { err = conn.SetReadDeadline(time.Now().Add(readTimeout)) // timeout if err != nil { log.Println("setReadDeadline failed:", err) } n, err := conn.Read(buffer) if err != nil { log.Println("Read failed:", err) //break } log.Println("count:", n, "msg:", string(buffer)) } }
輸出結果
2019/05/12 16:18:19 Read failed: read tcp 127.0.0.1:51718->127.0.0.1:8080: i/o timeout 2019/05/12 16:18:19 count: 0 msg: 2019/05/12 16:18:20 count: 28 msg: You are welcome. I'm server. 2019/05/12 16:18:22 Read failed: read tcp 127.0.0.1:51718->127.0.0.1:8080: i/o timeout 2019/05/12 16:18:22 count: 0 msg: You are welcome. I'm server. 2019/05/12 16:18:23 count: 28 msg: You are welcome. I'm server. 2019/05/12 16:18:25 Read failed: read tcp 127.0.0.1:51718->127.0.0.1:8080: i/o timeout 2019/05/12 16:18:25 count: 0 msg: You are welcome. I'm server. 2019/05/12 16:18:26 count: 28 msg: You are welcome. I'm server.