package nettools import ( "fmt" "golang.org/x/net/context" "net" "strconv" "time" ) type TcpPingResult struct { Time int Err error IP net.IP } func (tcpR *TcpPingResult) Result() int { return tcpR.Time } func (tcpR *TcpPingResult) Error() error { return tcpR.Err } func (tcpR *TcpPingResult) String() string { if tcpR.Err != nil { return fmt.Sprintf("%s", tcpR.Err) } else { return fmt.Sprintf("%s: time=%d ms", tcpR.IP.String(), tcpR.Time) } } type TcpPing struct { host string Port int Timeout time.Duration ip net.IP } func (tcpC *TcpPing) SetHost(host string) { tcpC.host = host tcpC.ip = net.ParseIP(host) } func (tcpC *TcpPing) Host() string { return tcpC.host } func (tcpC *TcpPing) Ping() IPingResult { return tcpC.PingContext(context.Background()) } func (tcpC *TcpPing) PingContext(ctx context.Context) IPingResult { ip := cloneIP(tcpC.ip) if ip == nil { var err error ip, err = LookupFunc(tcpC.host) if err != nil { return &TcpPingResult{0, err, nil} } } dialer := &net.Dialer{ Timeout: tcpC.Timeout, KeepAlive: -1, } t0 := time.Now() conn, err := dialer.DialContext(ctx, "tcp", net.JoinHostPort(ip.String(), strconv.FormatUint(uint64(tcpC.Port), 10))) if err != nil { return &TcpPingResult{0, err, nil} } defer conn.Close() return &TcpPingResult{int(time.Now().Sub(t0).Milliseconds()), nil, ip} } func NewTcpPing(host string, port int, timeout time.Duration) *TcpPing { return &TcpPing{ host: host, Port: port, Timeout: timeout, ip: net.ParseIP(host), } } var ( _ IPing = (*TcpPing)(nil) _ IPingResult = (*TcpPingResult)(nil) )