golang的net包设置超时有三个函数, 定义在net.Conn, 它是一个interface, 如下:

SetDeadline(t time.Time) error            // 设置读写超时, 如果超时, 会返回超时错误. 等同于同时设置以下两个函数.

SetReadDeadline(t time.Time) error   // 设置读超时, 如果超时, 会返回超时错误.

SetWriteDeadline(t time.Time) error   // 设置写超时, 如果超时, 会返回超时错误.

本文主要验证的是写超时, 并判断超时错误, 主要是通过reflect和unsafe把err转成(*net.OpError). 测试代码如下:

package main

import (
	"fmt"
	"net"
	"os"
	"reflect"
	"syscall"
	"time"
	"unsafe"
)

func main() {
	listener, err := net.Listen("tcp", "127.0.0.1:10299")
	if err != nil {
		fmt.Printf("listen fail, err: %v\n", err)
		os.Exit(-1)
	}
	defer listener.Close()

	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Printf("accept fail, err: %v\n", err)
			continue
		}
		fmt.Printf("accept: %s successfully!\n", conn.RemoteAddr())

		go write(conn)
	}
}

func write(c net.Conn) {
	defer c.Close()
	now := time.Now()
	begin := now.Local().UnixNano() / (1000 * 1000)

	// 为了验证超时, 在循环外设置, 2秒超时
	c.SetWriteDeadline(now.Add(time.Second * 2))

	for {
		if _, err := c.Write([]byte("Write Msg")); err != nil {
			// 这个错误是不能转换*net.OpError
			if err == syscall.EINVAL {
				return
			}

			// 转换成*net.OpError
			opErr := (*net.OpError)(unsafe.Pointer(reflect.ValueOf(err).Pointer()))
			if opErr.Err.Error() == "i/o timeout" {
				end := time.Now().Local().UnixNano() / (1000 * 1000)
				fmt.Printf("Write timeout! end: %d, begin: %d, timeOut: %dms", end, begin, end-begin)
				return
			}

			return
		}
		time.Sleep(time.Millisecond)
	}
}

测试结果如下:

 

结束:

这是通过指针转换并通过比较字符串的方式判断的, 如果哪位同学有更方便的方法, 请告知以下, 谢谢.