2012-06-18 4 views
5

Ich versuche, eine Datei über einen IHttpHandler zu übertragen, ist der Code ziemlich einfach. Wenn ich jedoch eine einzelne Übertragung starte, verbraucht es ungefähr 20% der CPU. Wenn ich dies auf 20 gleichzeitige Übertragungen skalieren würde, ist die CPU sehr hoch. Gibt es einen besseren Weg, um die CPU niedriger zu halten? Der Client-Code sendet nur Teile der Datei 64 KB gleichzeitig.File Transfer Essen eine Menge CPU

public void ProcessRequest(HttpContext context) 
{ 
     if (context.Request.Params["secretKey"] == null) 
     { 

     } 
     else 
     { 
      accessCode = context.Request.Params["secretKey"].ToString(); 
     } 

     if (accessCode == "test") 
     { 
      string fileName = context.Request.Params["fileName"].ToString(); 
      byte[] buffer = Convert.FromBase64String(context.Request.Form["data"]); 
      string fileGuid = context.Request.Params["smGuid"].ToString(); 
      string user = context.Request.Params["user"].ToString(); 

      SaveFile(fileName, buffer, user); 
     } 
} 

public void SaveFile(string fileName, byte[] buffer, string user) 
{ 
     string DirPath = @"E:\Filestorage\" + user + @"\"; 

     if (!Directory.Exists(DirPath)) 
     { 
      Directory.CreateDirectory(DirPath); 
     } 

     string FilePath = @"E:\Filestorage\" + user + @"\" + fileName; 
     FileStream writer = new FileStream(FilePath, File.Exists(FilePath) ? FileMode.Append : FileMode.Create, FileAccess.Write, FileShare.ReadWrite); 
     writer.Write(buffer, 0, buffer.Length); 
     writer.Close(); 
} 

Hier ist meine Kundennummer:

//Set filename from object 
       string FileName; 
       FileName = System.IO.Path.GetFileName(pubAttFullPath.ToString()); 

       //Open file 
       string file = System.IO.Path.GetFileName(pubAttFullPath.ToString()); 
       FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read); 
       //Chunk size that will be sent to Server 
       int chunkSize = 65536; 
       // Unique file name 
       string fileName = smGuid.ToString() + "_" + FileName; 
       int totalChunks = (int)Math.Ceiling((double)fileStream.Length/chunkSize); 
       // Loop through the whole stream and send it chunk by chunk; 
       for (int i = 0; i < totalChunks; i++) 
       { 
        bool doRecieve = true; 
        int cpt = 0; 
        do 
        { 
         int startIndex = i * chunkSize; 
         int endIndex = (int)(startIndex + chunkSize > fileStream.Length ? fileStream.Length : startIndex + chunkSize); 
         int length = endIndex - startIndex; 

         byte[] bytes = new byte[length]; 
         fileStream.Read(bytes, 0, bytes.Length); 


         //Request url, Method=post Length and data. 
         string requestURL = "http://localhost:16935/Transfer.doit"; 
         HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestURL); 
         // Wait 5 min for answer before close connection. 
         request.Timeout = 300000; 
         request.Method = "POST"; 
         request.ContentType = "application/x-www-form-urlencoded"; 

         // Chunk(buffer) is converted to Base64 string that will be convert to Bytes on the handler. 
         string requestParameters = @"fileName=" + fileName + @"&secretKey=test" + @"&currentChunk=" + i + @"&totalChunks=" + totalChunks + @"&smGuid=" + smGuid 
         + "&user=" + userSID.ToString() + 
         "&data=" + HttpUtility.UrlEncode(Convert.ToBase64String(bytes)); 

         // finally whole request will be converted to bytes that will be transferred to HttpHandler 
         byte[] byteData = Encoding.UTF8.GetBytes(requestParameters); 

         request.ContentLength = byteData.Length; 
         try 
         { 
          Stream writer = request.GetRequestStream(); 
          writer.Write(byteData, 0, byteData.Length); 
          writer.Close(); 
          // here we will receive the response from HttpHandler 
          StreamReader stIn = new StreamReader(request.GetResponse().GetResponseStream()); 
          string strResponse = stIn.ReadToEnd(); 
          stIn.Close(); 
          doRecieve = true; 
         } 
         catch (WebException webException) 
         { 
          if (webException.Status == WebExceptionStatus.ConnectFailure || 
           webException.Status == WebExceptionStatus.ConnectionClosed || 
           webException.Status == WebExceptionStatus.ReceiveFailure || 
           webException.Status == WebExceptionStatus.SendFailure || 
           webException.Status == WebExceptionStatus.Timeout) 
          { 
           Thread.Sleep(5000); 
           doRecieve = false; 
           cpt++; 
          } 
          else { 
           // if the exception is not those ones then get out 
           doRecieve = true; 
          } 
         } 
         catch (Exception e) 
         { 
          doRecieve = true; 
         } 
        } 
        // will try to send 3 times the current chunk before quitting 
        // can't try it so try it and give me the feedback 
        while(doRecieve == false && cpt < 3); 
       } 
+0

Worauf basieren Sie Ihre CPU-Nutzungsstatistiken? – CodingGorilla

+0

Starten eines Transfers und Überwachen von Perfmon. Ich bin der Einzige, der es benutzt. –

+0

Ist das auf einer Entwicklungsmaschine oder einem tatsächlichen Server? – CodingGorilla

Antwort

1

ich diese Theorie nicht getestet haben, aber mit FromBase64String arbeiten kann die Ursache sein. Ich habe this case gefunden, wo jemand mit dieser Methode keinen Speicher mehr hatte.

Sie könnten versuchen FromBase64Transform stattdessen, die entwickelt wurde, um einen Datenstrom zu behandeln.


Oder wenn Sie nicht brauchen, base64 aus irgendeinem Grund zu verwenden, überprüfen this solution from Scott Hanselman.

+0

Das ist interessant, ich gebe das eine Chance. Frage: Ich bin kein Base64-Experte oder irgendetwas, aber da mein Transport SSL ist, muss ich sogar das Byte-Array in base64 kodieren? –

+0

Ich wusste nicht, warum du base64 benutzt hast. Aber um Ihre Frage zu beantworten, müssen Sie die base64-Decodierung für eine über SSL übertragene Datei nicht durchführen. Überprüfen Sie diese Lösung (vorausgesetzt, Sie verwenden multipart/form-data) ... http://www.hanselman.com/blog/ABackToBasicsCaseStudyImplementingHTTPFileUploadWithASPNETMVCIncluntingTestsAndMocks.aspx –

+0

Ich habe versucht, diese Methode der Umwandlung der Byte-Array in eine Zeichenfolge zu verwenden (http://stackoverflow.com/questions/472906/net-string-to-byte-array-c-sharp) und dekodieren es zu einem Byte-Array auf dem HTTP-Handler und es immer noch 15% CPU verwendet (und die Datei beschädigt) ...nicht wirklich sicher, wie sonst kann ich das Byte-Array in den Parametern transportieren. –

Verwandte Themen