2013-07-15 54 views
0

我在下面的代碼中遇到了一些問題。它旨在從服務器接收文件。只要服務器在發送後斷開連接,它就可以100%正常工作。如果服務器斷開,文件傳輸纔會完成

如果服務器沒有斷開連接,那麼傳輸不會完成客戶端,並且客戶端繼續等待字節並且不會正確地跳出循環(當fr_block_sz == 0時),因爲它服務器在收到文件後斷開連接。它無休止地坐在循環中。

我希望能夠接收文件並保持連接打開後。有什麼建議?謝謝。

編輯:根據凱西的建議我現在正在監視通過下面的註釋代碼寫入的字節數量,但得到奇怪的行爲導致文件傳輸未正確完成。任何人都可以在我的代碼中看到任何錯誤嗎?謝謝。

編輯2:我發佈了關於我的問題的調試信息,試圖使其更清晰。

// Reciever of file (client) 
int TotalSize = 7374; // hardcoded file size to expect 
int FileSize = 0; // counter 
int fr_block_sz = 0; 
while ((fr_block_sz = recv(sd, revbuf, 1, 0)) > 0) //LENGTH == 512 
{ 
    if (fr_block_sz < 0) 
     if (errno == EAGAIN) 
      continue; 
     else 
      printf("File write failed"); 

     if (fr_block_sz == 0)   
      break; //done 

     // edit based on comment - does not change behavior 
     if(FilzeSize > TotalSize) 
     { 
      fr_block_sz = fr_block_sz - (FileSize - TotalSize); 
     }    

     int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr); 
     // add total bytes recvd every loop 
     FileSize += write_sz; 
     // if bytes recieved equals expect file size, break 
     if (FileSize >= TotalSize)// this is where my problem is, as sometimes 
            // FileSize == 7376 or 7672 instead of 7374 
            // When it fails, fr_block_sz == 24 which 
            // i don't think is right either. Even when 
            // set to break if FileSize > TotalSize, the 
            // loop still doesn't complete 
      break; 
     printf("Recieved size == %i of %i \n", FilzeSize, TotalSize); 

     if (write_sz < fr_block_sz) 
     { 
      printf("File write failed"); 
     } 

     bzero(revbuf, 1); 

} 
printf("Transfer complete \n"); 

控制檯輸出:

Recieved size == 512 of 7374 
Recieved size == 1024 of 7374 
Recieved size == 1368 of 7374 
Recieved size == 1880 of 7374 
Recieved size == 2392 of 7374 
Recieved size == 2736 of 7374 
Recieved size == 3248 of 7374 
Recieved size == 3760 of 7374 
Recieved size == 4104 of 7374 
Recieved size == 4616 of 7374 
Recieved size == 5128 of 7374 
Recieved size == 5472 of 7374 
Recieved size == 5984 of 7374 
Recieved size == 6496 of 7374 
Recieved size == 6840 of 7374 
Recieved size == 7352 of 7374 
Recieved size == 7376 of 7374 

一旦它送過來,客戶端將永遠等待在這裏的循環,沒有任何反應。然後我必須從控制檯手動停止程序,並且在程序停止後,只有4096個字節的文件被寫入。如果有人能夠闡明我的問題,或者說「正常」的方式來做到這一點,我會非常感激。謝謝。

編輯 - 固定(有點)。我發現一種方法可以使其每次可靠地工作100%,即通過更改LENGTH == 1,因此設置一個字節的緩衝區大小,並且如果內核正在爲字節寫入字節,則無法獲得短/長讀取。這可行,但顯然不是最快的解決方案。我仍然希望聽到其他人的聲音,並感謝你的幫助拉賈爾。

+0

所以,你必須看看服務器代碼,而不是 – bbonev

+0

無關:填充用零的緩衝器你與其他數據填充它之前,是沒有意義的。 – Casey

+0

凱西 - 固定,bbonev - 模糊評論,跟進。 – 4r4r4r

回答

1

問題是如果服務器未關閉連接,則客戶端不知道文件傳輸何時完成。你怎麼能傳達這個事實?

+0

我試過在發送後編碼服務器發送一個確認字節,它確實如此。它只在服務器斷開連接時起作用,然後客戶端寫入文件+ 1字節(這是確認),我無法弄清楚如何與循環內的特定字節進行比較。我假設我需要讓服務器發送一個字節,比如說0xAA,然後當客戶端獲得該字節時,它可以跳出循環? – 4r4r4r

+0

但是如果文件數據中有0xAA會發生什麼?請記住,你不能相信你從'recv'得到的數據塊與發送的方式完全一樣:你保證有序,但塊可以被拆分或合併。 – Casey

+0

提示:讓服務器在發送數據之前告訴客戶端數據的長度。 – Casey

1

我建議在客戶端和服務器之間遵循一些協議。一個例子,我可以顯示如下。

  1. 假設在服務器以及客戶端中,任何通信的前4個字節都是文件的大小。前4個字節由服務器爲每個建立的連接發送,直到文件完全發送。對於另一個文件/連接,服務器將再次發送4個字節,告訴文件的大小。
  2. 因此,客戶端的前4個字節將顯示需要處理的數據量。
  3. 客戶端最初只會讀取4個字節,而不是假設完整的緩衝區,因爲數據會將4個字節轉換爲整數,以便可以獲取確切的字節數。沒有必要確認字節,在這裏沒有用處。
  4. 一旦收到的字節數等於服務器發送的字節數假設文件被接收,服務器可以關閉連接。
  5. 在接收到文件中的字節數後,您可以假設下一個字節作爲服務器準備好發送另一個文件的指示符,或者如果您希望每個連接都接收一個文件,那麼如果您在緩衝區中接收到額外的字節,它。

可以有其他方式接收文件,以及我們有時在下載管理器中看到。比如使用相同的連接來分割文件或者使用相同的連接接收多個文件,但是我相信,一旦你設置了一個協議,增強就可以很容易地得到解決。

希望它有幫助。

只丟棄超過文件大小的任何字節。在fwrite之前嘗試以下內容。

if(FilzeSize > TotalSize) 
    { 
     fr_block_sz = fr_block_sz - (FilezeSize - TotalSize); 
    } 
    int write_sz = fwrite(revbuf, sizeof(char), fr_block_sz, fr); 

它應該寫入不包括最後2個字節的revbuf。

問候 Kajal

+0

感謝卡哈爾的迴應。我已經成功完成了步驟1 - 3(儘管有點不同)。然而,在第4步中,經常只是坐在循環中,文件不會成功完成,儘管它只有一次。 – 4r4r4r

+0

此外,對於第5步,您可以發佈一些僞代碼以瞭解如何忽略額外的字節,並且您是否看到我發佈的代碼有任何問題?謝謝。 – 4r4r4r

+0

酷!嘗試在同一連接中一個接一個地發送多個文件:) –

相關問題