2011-10-08 107 views
1

我做了一個客戶端&服務器建立通過套接字TCP連接,我試圖通過套接字發送二進制數據,但我只能派出TXT或PDF文件,我沒有運氣exe文件,我使用fread和fseek來讀取文件並將其分割成緩衝區。當我讀取整個exe文件時,它會被成功發送,但是當我分割它時,它會被髮送損壞!通過TCP發送二進制文件插座Ç

我讀了一些關於套接字的書,但我仍然不太瞭解,並且有一些問題。

可以在一個send()中發送整個文件嗎?或者我應該繼續以小塊形式發送它?

此外,爲什麼EXE文件在我發送塊時被損壞?

謝謝! (C語言)

客戶端代碼:

int bufSize = 10000; 
int sentBytes = 0; 


    FILE * pFile; 
    long remainingBytes; 
    char * buffer; 
    size_t result; 

    pFile = fopen ("D:\\file.exe" , "rb"); 
    fseek (pFile , 0 , SEEK_END); 
    remainingBytes = ftell (pFile); 
    rewind (pFile); 

int bufferSize = remainingBytes > bufSize ? bufSize : remainingBytes; 
buffer = (char*) malloc (sizeof(char)*bufferSize); 
send(Socket, (char*)&remainingBytes, 4, 0); 

while(remainingBytes > 0) 
{ 
    fseek (pFile , sentBytes , SEEK_SET); 
    result = fread(buffer,1,bufferSize,pFile); 
    if(bufferSize < remainingBytes) 
    { 
     send(Socket, buffer, bufferSize, 0); 
    } 
    else 
    { 
     send(Socket, buffer, remainingBytes, 0); 
     bufferSize = remainingBytes; 
    } 
    remainingBytes -= bufferSize; 
    sentBytes += bufferSize; 
} 

服務器代碼(C#)

 try 
     { 
      int bufferSize = 200; 
      int len = 0; 
      int receivedBytes = 0; 
      int remainingBytes = len; 
      byte[] length = new byte[4]; 
      //byte[] imgBuf = new byte[bufferSize]; 

      int current = 0; 
      List<byte[]> coming = new List<byte[]>(); 

      sockets[number].Receive(length,4,0); 

      len = BitConverter.ToInt32(length, 0); 
      remainingBytes = len; 

      bufferSize = len < bufferSize ? len : bufferSize; 

      while(receivedBytes < len) 
      { 
       if (remainingBytes > bufferSize) 
       { 
        coming.Add(new byte[bufferSize]); 
        //imgBuf = new byte[bufferSize]; 
        sockets[number].Receive(coming[current], bufferSize, 0); 
       } 
       else 
       { 
        coming.Add(new byte[remainingBytes]); 
        //imgBuf = new byte[remainingBytes]; 
        sockets[number].Receive(coming[current], remainingBytes, 0); 
        bufferSize = remainingBytes; 
       } 
       remainingBytes -= bufferSize; 
       receivedBytes += bufferSize; 
       current++; 
       //Array.Clear(imgBuf, 0, imgBuf.Length); 
      } 

      using (var stream = new FileStream(@"C:\receivedFile.exe",FileMode.Create)) 
      { 
       using (var binaryWriter = new BinaryWriter(stream)) 
       { 
        foreach (byte[] buffer in coming) 
        { 
         binaryWriter.Write(buffer); 
        } 
       } 

      } 
     } 
     catch (Exception ex) 
     { this.setText(ex.Message, textBox2); } 

編輯:感謝您的幫助,我得到它的工作:)

 try 
     { 
      int bufferSize = 1024 * 100; 
      int len = 0; 
      int receivedBytes = 0; 
      int remainingBytes = len; 
      int reached = 0; 

      byte[] length = new byte[4]; 
      byte[] imgBuf = new byte[bufferSize]; 

      int current = 0; 
      sockets[number].Receive(length,4,0); 

      len = BitConverter.ToInt32(length, 0); 
      remainingBytes = len; 

      bufferSize = len < bufferSize ? len : bufferSize; 
      imgBuf = new byte[len]; 

      while (reached < len) 
      { 
       reached += sockets[number].Receive(imgBuf, receivedBytes, remainingBytes, 0); 
       remainingBytes = len - reached; 
       receivedBytes = reached; 
       current++; 
       //Array.Clear(imgBuf, 0, imgBuf.Length); 
      } 

      using (var stream = new FileStream(@"C:\putty.exe",FileMode.Create)) 
      { 
       using (var binaryWriter = new BinaryWriter(stream)) 
       { 
         binaryWriter.Write(imgBuf); 
       } 
      } 
      Array.Clear(imgBuf, 0, imgBuf.Length); 
     } 
     catch (Exception ex) 
     { this.setText(ex.Message, textBox2); } 
+1

如果你從文件系統傳輸整個文件,你應該使用['的TransmitFile()'](http://msdn.microsoft.com/en-us/library/ms740565(VS.85)。 aspx)(如果在Windows上)或['sendfile()'](http://www.kernel.org/doc/man-pages/online/pages/man2/sendfile.2.html)(如果在Unix上) – millimoose

+0

感謝您的回答,但正如我所提到的,當我發送整個文件時,我完全沒有問題。只有當我嘗試以大塊發送時纔會出現此問題。 –

+0

我想說的是,不應該通過在內存中緩衝文件來從文件中發送文件,以便從性能的角度出發,無論文件是否在大塊中 - 使用其中一種函數會更高效。 – millimoose

回答

4

您不檢查您在sockets[number].Receive(coming[current], bufferSize, 0);實際收到的字節數。它不必與您聲明的緩衝區大小相等。 另外,如評論所述,將整個文件保存在內存中不是一個好主意。

+0

我不知道這是多麼有用,但它總是接收「bufferSize」相同的長度。 我編輯了這一行到 bytesReceived = sockets [number] .Receive(coming [current],bufferSize,0); –

+0

這是很難得到它在調試模式,只是添加一個例外bytesReceived!= coming [current] .Length並運行你的代碼 –

+0

我發現最後有什麼錯, 我不得不使用過載o函數接收 bytess =套接字[數字]。Receive(imgBuf,receivedBytes,bufferSize,0);的 而不是創建一個字節列表,並添加一個新的字節數組,每個收到,我與消息長度爲一個字節數組,並追加到它的所有請求 –

2

除了檢查接收的字節數,您需要檢查每個發送呼叫發送的字節數 - 如果你的TCP傳輸窗口填滿了,比你要求發送調用可能發送更少的數據,其中如果您需要重新發送未發送的數據。

一般情況下,你總是需要檢查你的系統的返回值調用來檢查所有不同的偏僻角落裏可能發生的情況。閱讀send(2)和recv(2)的手冊頁以獲取可能發生的所有事情的完整列表。