2013-08-05 30 views
0

我在一個示例java http服務器和.Net客戶端(在平板電腦上)工作。 使用我的http服務器,.Net客戶端必須能夠下載文件。HttpServer - HttpExchange - 尋找流

它的工作完美,但現在我必須能夠在連接中斷後恢復下載。

這裏是一些代碼:

Java服務器:(它是在一個單獨的線程啓動,因此run方法)。

public void run() { 

    try { 
     server = com.sun.net.httpserver.HttpServer.create(
       new InetSocketAddress(
         portNumber), this.maximumConnexion); 

     server.setExecutor(executor); 
     server.createContext("/", new ConnectionHandler(this.rootPath)); 
     server.start(); 


    } catch (IOException e1) { 
     //For debugging 
     e1.printStackTrace(); 
    } 

} 

我的HttpHandler:(只有部分處理GET請求)

/** 
* handleGetMethod : handle GET request. If the file specified in the URI is 
* available, send it to the client. 
* 
* @param httpExchange 
* @throws IOException 
*/ 
private void handleGetMethod(HttpExchange httpExchange) throws IOException { 

File file = new File(this.rootPath + this.fileRef).getCanonicalFile(); 

if (!file.isFile()) { 
    this.handleError(httpExchange, 404); 
} else if (!file.getPath().startsWith(this.rootPath.replace('/', '\\'))) { // windows work with anti-slash! 
    // Suspected path traversal attack. 
    System.out.println(file.getPath()); 
    this.handleError(httpExchange, 403); 
} else { 
    //Send the document. 


    httpExchange.sendResponseHeaders(200, file.length());  
    System.out.println("file length : "+ file.length() + " bytes."); 


    OutputStream os = httpExchange.getResponseBody(); 

    FileInputStream fs = new FileInputStream(file); 

    final byte[] buffer = new byte[1024]; 
    int count = 0; 
    while ((count = fs.read(buffer)) >= 0) { 
     os.write(buffer, 0, count); 
    } 
    os.flush(); 
    fs.close(); 
    os.close(); 
} 

}

現在我的.NET客戶端:(簡體)

try{ 

     Stream response = await httpClient.GetStreamAsync(URI + this.fileToDownload.Text); 


    FileSavePicker savePicker = new FileSavePicker(); 
    savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary; 
    // Dropdown of file types the user can save the file as 
    savePicker.FileTypeChoices.Add("Application/pdf", new List<string>() { ".pdf" }); 
    // Default file name if the user does not type one in or select a file to replace 
    savePicker.SuggestedFileName = "new doc"; 

    StorageFile file = await savePicker.PickSaveFileAsync(); 

    if (file != null) 
    { 

     const int BUFFER_SIZE = 1024*1024; 
     using (Stream outputFileStream = await file.OpenStreamForWriteAsync()) 
     { 
      using (response) 
      { 
       var buffer = new byte[BUFFER_SIZE]; 
       int bytesRead;       
       do 
       { 
        bytesRead = response.Read(buffer, 0, BUFFER_SIZE); 
        outputFileStream.Write(buffer, 0, bytesRead);         
       } while (bytesRead > 0); 
      } 
      outputFileStream.Flush(); 
     } 

    } 

} 
catch (HttpRequestException hre) 
{ //For debugging 
    this.Display.Text += hre.Message; 
    this.Display.Text += hre.Source; 
} 
catch (Exception ex) 
{ 
    //For debugging 
    this.Display.Text += ex.Message; 
    this.Display.Text += ex.Source; 
} 

所以,要恢復下載我想在.Net客戶端部分使用一些查找操作。 但每次我嘗試類似response.Seek(offset, response.Position);時,都會發生錯誤,通知該流不支持查找操作。 是的,它沒有,但我怎麼可以指定(在我的服務器端)使用可搜索的流? HttpExchange.setStreams方法可以用嗎? 或者,我不需要修改流,但要配置我的HttpServer實例?

謝謝。

+0

或者是否需要使用Accept-Range,Range和Content-Range HTTP標頭,然後只發送所需的內容。我不明白它是如何工作的,但似乎有點可疑...... – Zangdak

回答

1

那麼使用範圍,接受範圍和內容範圍字段的作品。爲了發送文件的正確部分並設置響應的標題,只需要做一些工作。

服務器可以通知客戶端,它通過設置接受-範圍字段支持範圍字段:

responseHeader.set("Accept-Ranges", "bytes"); 

然後設置時,部分文件被髮送的內容範圍字段:

responseHeader.set("Content-range", "bytes " + this.offSet + "-" + this.range + "/" + this.fileLength); 

最後,返回代碼必須設置爲206(部分內容)。

有關範圍的詳細信息,接受,範圍和內容範圍字段看到http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

NB:歌劇12.16使用領域「範圍」繼續下載,但似乎IE 10和Firefox 22不使用此領域。可能是我最初尋找的一些可尋求的流。如果有人有這個答案,我會很高興閱讀它=)。

+0

另一件事:HttpServer只使用提供的HttpHandler的一個實例。如果你想使用一些私有屬性來處理每個請求,這可能是一個問題。事實上,即使有合適的執行者,這些字段也會在所有傳入的請求中共享。我用另一個類來處理我的請求,HttpHandler只爲每個請求創建這個類的一個新實例。 – Zangdak