Golang如何检测端口状态

Golang如何检测端口状态 我想检查端口状态。我知道有很多端口扫描器的实现,但大多数实现仅在没有抛出错误时假定端口是开放的,否则就认为不是。

func GetPortState(network string, address string, timeoutInMilliseconds int) {
	timeout := time.Duration(timeoutInMilliseconds) * time.Millisecond

	connection, connectionError := net.DialTimeout(network, address, timeout)

	if connectionError != nil {
		// inspect error

		// return state ...
	}

	defer func() {
		connectionCloseError := connection.Close()

		if connectionCloseError != nil {
			// return error
		}
	}()

	// return state
}

有人能帮忙实现这个函数,使其正常工作吗?

提前感谢


更多关于Golang如何检测端口状态的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

它们中的大多数仅假设在没有抛出错误的情况下端口是开放的,否则就不是。

那么,是如何定义一个开放端口的呢?

更多关于Golang如何检测端口状态的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


要实现一个可靠的端口状态检测函数,需要处理多种网络错误情况。以下是完整的实现示例:

package main

import (
    "errors"
    "fmt"
    "net"
    "strings"
    "time"
)

type PortState int

const (
    PortOpen PortState = iota
    PortClosed
    PortFiltered
    PortError
)

func GetPortState(network string, address string, timeoutInMilliseconds int) (PortState, error) {
    timeout := time.Duration(timeoutInMilliseconds) * time.Millisecond
    
    conn, err := net.DialTimeout(network, address, timeout)
    
    if err != nil {
        // 分析错误类型以确定端口状态
        errStr := err.Error()
        
        // 连接被拒绝通常表示端口关闭
        if strings.Contains(errStr, "connection refused") {
            return PortClosed, nil
        }
        
        // 超时通常表示端口被过滤
        if strings.Contains(errStr, "timeout") || 
           strings.Contains(errStr, "i/o timeout") {
            return PortFiltered, nil
        }
        
        // 网络不可达
        if strings.Contains(errStr, "no route to host") ||
           strings.Contains(errStr, "network is unreachable") {
            return PortFiltered, err
        }
        
        // 其他错误
        return PortError, err
    }
    
    defer func() {
        if conn != nil {
            conn.Close()
        }
    }()
    
    return PortOpen, nil
}

// 辅助函数,获取可读的状态描述
func (ps PortState) String() string {
    switch ps {
    case PortOpen:
        return "OPEN"
    case PortClosed:
        return "CLOSED"
    case PortFiltered:
        return "FILTERED"
    case PortError:
        return "ERROR"
    default:
        return "UNKNOWN"
    }
}

// 使用示例
func main() {
    // 测试常见端口
    testCases := []struct {
        network string
        address string
        timeout int
    }{
        {"tcp", "google.com:80", 3000},
        {"tcp", "localhost:22", 1000},
        {"tcp", "127.0.0.1:9999", 2000},
        {"tcp", "192.168.1.1:80", 1000},
    }
    
    for _, tc := range testCases {
        state, err := GetPortState(tc.network, tc.address, tc.timeout)
        
        fmt.Printf("检查 %s://%s\n", tc.network, tc.address)
        fmt.Printf("状态: %s", state)
        
        if err != nil {
            fmt.Printf(" 错误: %v", err)
        }
        fmt.Println()
        fmt.Println("---")
    }
}

对于更精确的错误处理,可以使用类型断言:

func GetPortStateWithDetailedError(network string, address string, timeoutInMilliseconds int) (PortState, error) {
    timeout := time.Duration(timeoutInMilliseconds) * time.Millisecond
    
    conn, err := net.DialTimeout(network, address, timeout)
    
    if err != nil {
        var netErr net.Error
        var opErr *net.OpError
        
        switch {
        case errors.As(err, &netErr) && netErr.Timeout():
            return PortFiltered, nil
        case errors.As(err, &opErr):
            // 检查操作错误的具体类型
            if opErr.Op == "dial" {
                if strings.Contains(opErr.Err.Error(), "connection refused") {
                    return PortClosed, nil
                }
            }
            return PortError, err
        default:
            return PortError, err
        }
    }
    
    defer conn.Close()
    return PortOpen, nil
}

如果需要检查UDP端口状态:

func CheckUDPPort(address string, timeoutInMilliseconds int) (PortState, error) {
    timeout := time.Duration(timeoutInMilliseconds) * time.Millisecond
    
    udpAddr, err := net.ResolveUDPAddr("udp", address)
    if err != nil {
        return PortError, err
    }
    
    conn, err := net.DialUDP("udp", nil, udpAddr)
    if err != nil {
        return PortError, err
    }
    defer conn.Close()
    
    conn.SetDeadline(time.Now().Add(timeout))
    
    // 发送测试数据(可选)
    _, err = conn.Write([]byte{0x00})
    if err != nil {
        return PortError, err
    }
    
    // 尝试读取响应
    buffer := make([]byte, 1024)
    _, err = conn.Read(buffer)
    
    if err != nil {
        if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
            // UDP无响应通常表示端口开放或被过滤
            return PortOpen, nil
        }
        return PortError, err
    }
    
    return PortOpen, nil
}

这个实现提供了:

  1. 明确的端口状态枚举
  2. 详细的错误分析
  3. 支持TCP和UDP协议
  4. 可配置的超时时间
  5. 清晰的错误分类
回到顶部