【发布时间】:2018-03-20 14:06:30
【问题描述】:
/* Keep Alive Client*/
HttpClient{
Client: &http.Client{
Transport: &http.Transport{
Dial: (&net.Dialer{
Timeout: dialTimeout,
KeepAlive: dialTimeout * 60,
}).Dial,
DisableKeepAlives: false,
MaxIdleConnsPerHost: idleConnectionsPerHost,
},
},
Timeout: 5 * time.Second,
}
/* Execute Request */
timeoutContext, cancelFunction := context.WithTimeout(context.Background(), self.Timeout)
defer cancelFunction()
if response, err = self.Client.Do(request.WithContext(timeoutContext)); err == nil {
defer response.Body.Close()
/* Check If Request was Successful */
statusCode = response.StatusCode
if response.StatusCode == http.StatusOK {
/* Read Body & Decode if Response came & unmarshal entity is supplied */
if responseBytes, err = ioutil.ReadAll(response.Body); err == nil && unmarshalledResponse != nil {
//Process Response
}
} else {
err = errors.New(fmt.Sprintf("Non 200 Response. Status Code: %v", response.StatusCode))
}
}
在 Golang 中,只要 Keep-Alive 连接中的请求超时,该连接就会丢失并被重置。对于上面的代码,如果超时,在 Wireshark 中查看数据包表明 RST 是由客户端发送的,因此不再重用连接。
事件尝试使用 Httpclient 的 Timeout 而不是 ContextWithTimeout,但在连接被重置的地方有类似的发现。
无论如何,即使在请求超时的情况下,我们也可以保持已建立的 keep-alive 连接。
【问题讨论】:
-
如果请求超时,则意味着它在某种意义上还没有“完成”,所以它处于未定义状态。你不能重复使用它。
-
如果您希望重用连接,您还需要确保您正在阅读整个响应正文。在您的代码中,任何非 200 响应代码都将导致响应正文不被读取,因此连接不会被重用。
-
@Adrian 在我目前的理解中 defer response.Body.Close() 也应该读取响应正文并丢弃它。让我知道它是否有任何参考不正确。
-
Close关闭流,它不会读取任何未读的正文内容。 -
我也试过了,但在 Wireshark 中观察到时仍然发送 RST。
标签: go tcp keep-alive