httpリクエストで利用可能なさまざまなタイムアウトを読んでいて、リクエストの合計時間でハードデッドラインとして機能するようです。httpダウンロードでインアクティビティタイムアウトを実装するにはどうすればいいですか
私はhttpダウンロードを実行していますが、私は自分のユーザー接続について何も知らないし、低速接続でタイムアウトしたくないため、最初のハンドシェイクを超えてハードタイムアウトを実装したくありません。私が理想的に思っているのは、何も何もダウンロードされていない一定期間の無活動の後にタイムアウトすることです。組み込みとしてこれを行う方法はありますか、ファイルの記述に基づいて中断する必要がありますか?
作業コードは分離するのが少し難しいですが、これらは関連する部分だと思っていますが、進捗を提供する別のループがありますが、これを使用してダウンロードを中断するために少しリファクタリングする必要があります:
このへの入力を持っていたすべての人に// httspClientOnNetInterface returns an http client using the named network interface, (via proxy if passed)
func HttpsClientOnNetInterface(interfaceIP []byte, httpsProxy *Proxy) (*http.Client, error) {
log.Printf("Got IP addr : %s\n", string(interfaceIP))
// create address for the dialer
tcpAddr := &net.TCPAddr{
IP: interfaceIP,
}
// create the dialer & transport
netDialer := net.Dialer{
LocalAddr: tcpAddr,
}
var proxyURL *url.URL
var err error
if httpsProxy != nil {
proxyURL, err = url.Parse(httpsProxy.String())
if err != nil {
return nil, fmt.Errorf("Error parsing proxy connection string: %s", err)
}
}
httpTransport := &http.Transport{
Dial: netDialer.Dial,
Proxy: http.ProxyURL(proxyURL),
}
httpClient := &http.Client{
Transport: httpTransport,
}
return httpClient, nil
}
/*
StartDownloadWithProgress will initiate a download from a remote url to a local file,
providing download progress information
*/
func StartDownloadWithProgress(interfaceIP []byte, httpsProxy *Proxy, srcURL, dstFilepath string) (*Download, error) {
// start an http client on the selected net interface
httpClient, err := HttpsClientOnNetInterface(interfaceIP, httpsProxy)
if err != nil {
return nil, err
}
// grab the header
headResp, err := httpClient.Head(srcURL)
if err != nil {
log.Printf("error on head request (download size): %s", err)
return nil, err
}
// pull out total size
size, err := strconv.Atoi(headResp.Header.Get("Content-Length"))
if err != nil {
headResp.Body.Close()
return nil, err
}
headResp.Body.Close()
errChan := make(chan error)
doneChan := make(chan struct{})
// spawn the download process
go func(httpClient *http.Client, srcURL, dstFilepath string, errChan chan error, doneChan chan struct{}) {
resp, err := httpClient.Get(srcURL)
if err != nil {
errChan <- err
return
}
defer resp.Body.Close()
// create the file
outFile, err := os.Create(dstFilepath)
if err != nil {
errChan <- err
return
}
defer outFile.Close()
log.Println("starting copy")
// copy to file as the response arrives
_, err = io.Copy(outFile, resp.Body)
// return err
if err != nil {
log.Printf("\n Download Copy Error: %s \n", err.Error())
errChan <- err
return
}
doneChan <- struct{}{}
return
}(httpClient, srcURL, dstFilepath, errChan, doneChan)
// return Download
return (&Download{
updateFrequency: time.Microsecond * 500,
total: size,
errRecieve: errChan,
doneRecieve: doneChan,
filepath: dstFilepath,
}).Start(), nil
}
更新 感謝。
私が選んだ解決策よりも一般化されている完全に実行可能なアプローチのように思われるので、私はJimBの答えを受け入れました。
私の場合は、すでにファイルサイズを監視していたので、x秒間変化しなければ名前付きエラーが発生しました。既存のエラー処理を使って指定されたエラーを見つけ出し、そこからダウンロードを再試行するほうがはるかに簡単でした。
バックグラウンドで私のアプローチでクラッシュする可能性がありますが(これは後でシグナリングで修正できます)、これは短時間実行するアプリケーション(インストーラ)なので、これは許容されます(少なくとも耐えられる)
'io.Copy'を自分で書いたもので置き換えることができます。個々の' Read'コールのタイムアウトを設定し、何かをチャンネルなどに書き込むことでこれまでのコピーデータ量を通知することもできます。 – Krom
それは悪い解決策ではなく、私が計画していたものよりもきれいだと感じています - 提案に感謝 – WebweaverD
'io.Copy'を置き換える方がはるかに複雑であると考えています。素敵なプロパティ:[関連性があるかもしれません](https://groups.google。com/d/msg/golang-nuts/434c3YInH_M/3Qd7C0uDUqQJ) – Krom