go循环发送http请求经常报错超时

lgy1027 · 2019-05-13 18:27:31 · 9890 次点击 · 预计阅读时间 2 分钟 · 大约8小时之前 开始浏览    
这是一个创建于 2019-05-13 18:27:31 的文章,其中的信息可能已经有所发展或是发生改变。

代码如下:

func NewHttping(method, protocol string, timeoutDuration time.Duration) *Httping {
    return &Httping{
        Method:   method,
        Protocol: protocol,
        Client:      &http.Client{
            Timeout: timeoutDuration,
            Transport: &http.Transport{
                TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
            },
        },
    }
}

func (httping *Httping) Ping(t model.TargetIp) (float64, *http.Response, error) {
    var resp *http.Response
    var body io.Reader
    if httping.Method == "POST" {
        body = bytes.NewBufferString("{}")
    }
    req, err := http.NewRequest(httping.Method, fmt.Sprintf("%s://%s:%d", httping.Protocol, t.IP, t.Port), body)
    if t.Header != "" {
        head := map[string]interface{}{}
        err := json.Unmarshal([]byte(t.Header), &head)
        if err != nil {
            seelog.Error("[func:httping is err]", err.Error())
        }
        for key, val := range head {
            req.Header.Add(key, val.(string))
        }
    }
    if err != nil {
        return 0, nil, err
    }

    duration, errIfce := utils.TimeIt(func() interface{} {
        resp, err = httping.Client.Do(req)
        return err
    })
    if errIfce != nil {
        err := errIfce.(error)
        return 0, nil, err
    }
    return duration, resp, nil
}

报错信息如下:

2019-05-13/18:15:03 [Error] httping.go [func:HTTP StartPing ] www.youku.com - failed: Get http://www.youku.com:80: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)

我这边设置的超时时间是10s,程序以间隔2秒的时间差循环发送求情,但是经常报错超时,我想着youku不至于这样吧,麻烦大神帮我看看问题出在什么地方了吗


有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

9890 次点击  
加入收藏 微博
6 回复  |  直到 2019-05-14 19:38:03
polaris
polaris · #1 · 6年之前

你是不是一直用的一个连接呢?

lgy1027
lgy1027 · #2 · 6年之前
polarispolaris #1 回复

你是不是一直用的一个连接呢?

没,在每四次请求后会重新调用NewHttping()生成新的client

polaris
polaris · #3 · 6年之前

Response.Body Close 了吗?调用 Ping 的代码发来看看

lgy1027
lgy1027 · #4 · 6年之前
func (httping *Httping) StartPing(t model.TargetIp, wg *sync.WaitGroup) {
    times := make([]string, t.Count)
    stat := &model.PingSt{
        Protocol: httping.Protocol,
        AName:    inital.Cfg.Name,
    }
    stat.ShortT = -1

    speedTemp := 0.0
    for i := 0; i < t.Count; i++ {
        delay, resp, err := httping.Ping(t)
        if err == nil {
            defer resp.Body.Close()
            length, _ := io.Copy(ioutil.Discard, resp.Body)
            if resp.StatusCode != 200 {
                stat.Status = resp.Status
                stat.RespCode = resp.StatusCode
                seelog.Errorf("[func:HTTP StartPing ] %s - failed: status:%s \n", t.IP, resp.Status)
                stat.LostN = stat.LostN + 1
                times[stat.SendN] = "-1"
            } else {
                speed := float64(length) / (delay / 1000) / 1024
                stat.Status = resp.Status
                stat.RespCode = resp.StatusCode
                stat.SumT += delay
                speedTemp += speed
                if stat.LongT < delay {
                    stat.LongT = delay
                }
                if stat.ShortT == -1 || stat.ShortT > delay {
                    stat.ShortT = delay
                }
                stat.RecvN = stat.RecvN + 1
                times[stat.SendN] = fmt.Sprintf("%.3f", delay)
            }
        } else {
            seelog.Errorf("[func:HTTP StartPing ] %s - failed: %s\n", t.IP, err.Error())
            stat.LostN = stat.LostN + 1
            times[stat.SendN] = "-1"
        }
        stat.SendN = stat.SendN + 1
        stat.Pat = (float64(stat.LostN) / float64(stat.SendN)) * 100
        time.Sleep(2 * time.Second)
    }

    pingTimes := ""
    for i := 0; i < len(times); i++ {
        if i == len(times)-1 {
            pingTimes += times[i]
        } else {
            pingTimes += times[i] + ","
        }
    }
    stat.Times = pingTimes
    if stat.RecvN > 0 {
        stat.MrTime = stat.SumT / float64(stat.RecvN)
        f, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", speedTemp/float64(stat.RecvN)), 64)
        stat.Speed = f
    } else {
        stat.MrTime = 0.0
        stat.Speed = 0.0
    }

    wg.Done()
}
lgy1027
lgy1027 · #5 · 6年之前
polarispolaris #3 回复

Response.Body Close 了吗?调用 Ping 的代码发来看看

我这边做了个定时器,代码

timeoutDuration, err := time.ParseDuration(target.Timeout)
if err != nil {
    seelog.Error("[func:Start HTTP-PING is duration err ]", err)
}
pinger = service.NewHttping(strings.ToUpper(target.Method), strings.ToLower(target.Protocol),timeoutDuration)
polaris
polaris · #6 · 6年之前

我就知道有问题。

在循环里面使用 defer resp.Body.Close(),这是大忌。函数结束才会 Close 啊

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传