|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
 | func httpsHostBindIp(domain, urlStr, ip string, timeout int, wg *sync.WaitGroup) {
    defer wg.Done()
    //异常处理
    defer func() {
        //捕获异常
        err := recover()
        if err != nil {
            //条件判断,是否存在异常
            //存在异常,抛出异常
            log.Printf("http请求 %s 出错:%v\n", urlStr, err)
        }
    }()
    if timeout <= 0 || timeout > 10000 {
        timeout = 3000
    }
    urlObj, err := url.Parse(urlStr)
    if err != nil {
        log.Printf("url.Parse %s Error: %v\n", urlStr, err)
    }
    request, _ := http.NewRequest("GET", urlObj.String(), bytes.NewBuffer([]byte{}))
    defer request.Body.Close()
    request.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36")
    var response *http.Response
    // 一、 绑定固定的IP
    // 1. 先准备一个Dialer对象
    dialer := &net.Dialer{
        Timeout: time.Duration(timeout) * time.Millisecond,
    }
    transport := &http.Transport{
        // 2. 插入特别的改写条件,然后继续利用原先的DialContext逻辑
        DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
            portSlice := strings.Split(addr, ":")
            port := portSlice[1]
            addr = ip + ":" + port
            return dialer.DialContext(ctx, network, addr)
        },
    }
    // 客户端重定向
    client := &http.Client{
        //http客户端重定向
        CheckRedirect: func(req *http.Request, via []*http.Request) error {
            if len(via) >= 10 {
                return errors.New("stopped after 10 redirects")
            }
            return nil
        },
        Transport: transport,
        Timeout:   time.Duration(timeout) * time.Millisecond,
    }
    var respCode string
    starttime := time.Now()
    response, err = client.Do(request)
    if err != nil {
        // 判断错误是否为超时
        if urlErr, ok := err.(*url.Error); ok {
            if urlErr.Timeout() {
                log.Printf("探测 %s %s 请求超时:%s\n", urlStr, ip, err)
                respCode = "0"
            } else {
                log.Printf("探测 %s %s 请求时发生其他网络错误:%s\n", urlStr, ip, err)
                respCode = "1"
            }
        } else {
            log.Printf("探测 %s %s 请求时发生非网络错误:%s\n", urlStr, ip, err)
            respCode = "2"
        }
    } else {
        defer response.Body.Close()
        respCode = strconv.Itoa(response.StatusCode)
        log.Printf("探测结果:%s ,IP:%s,状态码 %v\n", urlStr, ip, respCode)
    }
    endtime := time.Since(starttime)
    Observer(domain, urlStr, ip, endtime.Seconds())
    log.Printf("完成时间:%s IP:%s 请求花费了 %.2fs 时间\n", domain, ip, endtime.Seconds())
    IncreaseCounter(domain, urlStr, ip, respCode)
}
 |