网络通讯中,为了防止长时间无响应的状况,常常会用到网络链接超时、读写超时的设置。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.