2017-12-06 20 views
0

환경 : Windows Server 2012 R2 64 비트. C# .NET Framework 버전 4.5.1.여러 스레드 사이에서 단일 HttpClient를 다시 사용할 때 소켓 부족 - TIMED_WAIT 연결의 1000 초 남음

내가하여 SharePoint 2013 사이트에서 파일들을 다운로드하는이 프로그램을 사용하는 것을 시도하고있다 : https://github.com/nddipiazza/Sharepoint-Exporter

이 프로젝트에서 파일을 다운로드 요청을 끌어 [FileDownloader.cs] [1] 파일이 BlockingCollection에 저장하고 파일에 다운로드합니다. 나는이 프로그램을 실행할 때

내가 꽤 빨리 소켓 오류 때리게 : 나는 너무 열심히이 코드를 타격하고 같은

System.AggregateException: One or more errors occurred. ---> System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted 10.5.50.2:443 
    at System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult) 
    at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Exception& exception) 
    --- End of inner exception stack trace --- 
    at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult) 
    at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar) 
    --- End of inner exception stack trace --- 
    --- End of inner exception stack trace --- 
    at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification) 
    at SpPrefetchIndexBuilder.FileDownloader.attemptToDownload(FileToDownload toDownload, Int32 numRetry) 
---> (Inner Exception #0) System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted 10.5.50.2:443 
    at System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult) 
    at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Exception& exception) 
    --- End of inner exception stack trace --- 
    at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult) 
    at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar) 
    --- End of inner exception stack trace ---<--- 

를 기본적으로 같다 :

public void AttemptToDownload(FileToDownload toDownload, int numRetry) 
{ 
    try 
    { 
     var responseResult = client.GetAsync(SpPrefetchIndexBuilder.topParentSite + toDownload.serverRelativeUrl); 
     if (responseResult.Result != null && responseResult.Result.StatusCode == System.Net.HttpStatusCode.OK) 
     { 
      using (var memStream = responseResult.Result.Content.ReadAsStreamAsync().GetAwaiter().GetResult()) 
      { 
       using (var fileStream = File.Create(toDownload.saveToPath)) 
       { 
        memStream.CopyTo(fileStream); 
       } 
      } 
      Console.WriteLine("Thread {0} - Successfully downloaded {1} to {2}", Thread.CurrentThread.ManagedThreadId, toDownload.serverRelativeUrl, toDownload.saveToPath); 
     } 
     else 
     { 
      Console.WriteLine("Got non-OK status {0} when trying to download url {1}", responseResult.Result.StatusCode, SpPrefetchIndexBuilder.topParentSite + toDownload.serverRelativeUrl); 
     } 
    } 
    catch (Exception e) 
    { 
     if (numRetry >= NUM_RETRIES) 
     { 
      Console.WriteLine("Gave up trying to download url {0} to file {1} after {2} retries due to error: {3}", SpPrefetchIndexBuilder.topParentSite + toDownload.serverRelativeUrl, toDownload.saveToPath, NUM_RETRIES, e); 
     } 
     else 
     { 
      AttemptToDownload(toDownload, numRetry + 1); 
     } 
    } 
} 

뭔가 잘못 거기 방법으로 I HttpClient를 사용하고 있습니까? 모든 포럼을 읽었으며 정적 참조를 다시 사용하라고 말하고 있습니다. 모든 스레드는 동일한 정적 HttpClient 참조를 공유합니다.

여기는 다운로드가 몇 분 동안 실행 된 때의 netstat -a -o -n입니다. TIMED_WAIT이 (가) 많이 있습니다. https://pastebin.com/GTYmqwue이 테스트에서는 포트 80에서 SharePoint를 사용하고있었습니다. 왜 그런가요?

몇 분 후에 다시 실행하면 TIMED_WAIT의 수가 수백 개 증가합니다. 어떤 종류의 누수가 있어야 하나?

HttpClient가 1000 개의 TIMED_WAIT 연결을 그대로 두는 이유는 무엇입니까? 어떻게 닫을 수 있습니까?

ServiePointManager.DefaultConnectionLimit = numThreads으로 설정하려고했으나 여전히 연결 수가 1000 개가됩니다.

+0

어떤 운영 체제입니까? –

+0

중복 된 것으로 보입니다. - https://stackoverflow.com/questions/2960056/trying-to-run-multiple-http-requests-in-parallel-but-being-limited-by-windows –

+0

단일 HttpClient에는 한 번에 처리 할 수있는 많은 동시 요청 만 있습니다. 루프에서 비동기를 사용하는 경우 1000s의 요청을 쉽게 시작하는 것이 어렵지 않습니다. –

답변

1

나는 마침내

실수로 내가

client.Timeout = TimeSpan.FromSeconds(15);이 변경 client.Timeout = TimeSpan.FromMinutes(5);

정말 공격적이 지금은 연결이 더 이상 유출되지 않는다 생각했다 그것을 알아 냈다고 생각합니다.