2011-01-22 76 views
1

我學習HTTP,並決定使用TcpClient從互聯網下載文件。從HTTP服務器通過TcpClient下載文件

private void requireBtn_Click(object sender, EventArgs e) { 
    var client = new TcpClient(addressBox.Text, 80); 
    var networkStream = client.GetStream(); 

    var sWriter = new StreamWriter(networkStream, Encoding.Default); 
    foreach (string querLine in queryBox.Lines) { 
    sWriter.WriteLine(querLine); 
    } 
    sWriter.WriteLine(); 
    sWriter.Flush(); 

    string responceText = ""; 

    var sReader = new StreamReader(networkStream); 
    string respLine; 
    while ((respLine = sReader.ReadLine()).Length > 0) { 
    responceText += respLine + "\r\n"; 
    } 

    responceBox.Text = responceText; 

    Regex reContentLength = new Regex(@"(?<=Content-Length:\s)\d+", RegexOptions.IgnoreCase); 
    Int32 contentLength = Int32.Parse(reContentLength.Match(responceText).Value); 
    this.Text = contentLength.ToString(); 

    if (networkStream.CanRead) { 
    var fileStream = new FileStream(@"C:\img.png", FileMode.Create); 

    byte[] buffer = new byte[1024]; 

    int numberOfBytesRead = 0; 
    do { 
     numberOfBytesRead = networkStream.Read(buffer, 0, buffer.Length); 
     fileStream.Write(buffer, 0, numberOfBytesRead); 
    } 
    while (networkStream.DataAvailable); 

    fileStream.Flush(); 
    fileStream.Close(); 

    MessageBox.Show("Done!"); 
    } 
    else 
    MessageBox.Show("Fail!"); 

    client.Close(); 
} 

但下載的文件已損壞。我不明白爲什麼... Source file

回答

0

我建議使用CONTENTLENGTH而不是networkStream.DataAvailable檢測在數據傳輸完成。 DataAvailable僅表示存在由OS堆棧接收到的數據,但取決於您檢查條件時可能未到達的網絡路由和碎片,因此您不再過早接收該數據。

要證明或反駁這一點,您可以在程序下載的內容與普通瀏覽器下載的內容之間進行二進制文件比較。如果前者被截斷,那麼我們發現了這個問題。

0

您需要使用Content-Length標頭中的值(它可以大於32位整數,btw)。繼續閱讀,直到收到許多字節。

但是,服務器可能完全不使用Content-Length標頭。它可以使用包含chunked編碼的Transfer-Encoding標頭,或者根本不使用任何標頭。 HTTP定義了幾種不同的方式來確定數據的長度,並且您應該儘可能多地支持以考慮各種服務器。請參閱RFC 2616第4.3和4.4節,瞭解您需要遵循的特定規則。

1
private void requireBtn_Click(object sender, EventArgs e) { 
    string host = "atomAltera.SkyHost.ge"; 
    string query = "GET /mems.txt HTTP/1.1\r\n" + 
       "Host: atomAltera.SkyHost.ge\r\n" + 
       "User-Agent: NuclightWeb\r\n" + 
       "Connection: close\r\n"+ 
       "\r\n"; 

    var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); 
    client.Connect(host, 80); 

    var networkStream = new NetworkStream(client); 

    var bytes = Encoding.Default.GetBytes(query); 
    networkStream.Write(bytes, 0, bytes.Length); 


    var bReader = new BinaryReader(networkStream, Encoding.Default); 

    string responce = ""; 
    string line; 
    char c; 

    do { 
    line = ""; 
    c = '\u0000'; 
    while (true) { 
     c = bReader.ReadChar(); 
     if (c == '\r') 
     break; 
     line += c; 
    } 
    c = bReader.ReadChar(); 
    responce += line + "\r\n"; 
    } while (line.Length > 0); 

    responceBox.Text = responce; 

    Regex reContentLength = new Regex(@"(?<=Content-Length:\s)\d+", RegexOptions.IgnoreCase); 
    Int32 contentLength = Int32.Parse(reContentLength.Match(responce).Value); 

    this.Text = contentLength.ToString(); 

    var fileStream = new FileStream(@"C:\m.txt", FileMode.Create); 

    byte[] buffer = new byte[4 * 1024]; 
    int n = 0; 
    int read = 0; 

    while (n < contentLength) { 
    if (networkStream.DataAvailable) { 
     read = networkStream.Read(buffer, 0, buffer.Length); 
     n += read; 
     fileStream.Write(buffer, 0, read); 
    } 
    } 

    fileStream.Flush(); 
    fileStream.Close(); 


    client.Close(); 
} 

It Works!可能是StreamReader讀取多餘的字節?

相關問題