2012-11-06 69 views
1

我試圖通過TCP套接字發送數據塊。服務器代碼執行以下操作:從TCP套接字讀取錯誤的數據

#define CHECK(n) if((r=n) <= 0) { perror("Socket error\n"); exit(-1); } 
int r; 

//send the number of blocks 
CHECK(write(sockfd, &(storage->length), 8)); //p->length is uint64_t 

for(p=storage->first; p!=NULL; p=p->next) { 
    //send the size of this block 
    CHECK(write(sockfd, &(p->blocksize), 8)); //p->blocksize is uint64_t 

    //send data 
    CHECK(write(sockfd, &(p->data), p->blocksize)); 
} 

在客戶端,我讀的大小,然後將數據(相同的檢查萬客隆):

CHECK(read(sockfd, &block_count, 8)); 
for(i=0; i<block_count; i++) { 
    uint64_t block_size; 
    CHECK(read(sockfd, &block_size, 8)); 

    uint64_t read_in=0; 
    while(read_in < block_size) { 
    r = read(sockfd, data+read_in, block_size-read_in); //assume data was previously allocated as char* 
    read_in += r; 
    } 
} 

這隻要工作完全正常的客戶端和服務器在同一臺機器上運行,但只要我通過網絡嘗試完成,它在某些時候會失敗。特別是,第一300-400塊(A〜587字節)左右做工精細,但後來我得到一個不正確的block_size閱讀:

received block #372 size : 586 
read_in: 586 of 586 
received block #373 size : 2526107515908 

然後它崩潰了,很明顯。 我的印象是TCP協議確保沒有數據丟失,並且所有信息都按正確的順序接收,但是考慮到它已經在本地工作,那麼這怎麼可能?我的錯誤在哪裏?

+0

您是否檢查過服務器中的列表實際上是否有效?即'p-> next'對於最後一個節點是'NULL'。 –

回答

4

無法保證當您閱讀block_countblock_size時,您將一次讀取全部8個字節。

1

我的印象是,TCP協議保證沒有數據丟失 ,一切都在正確的順序

是接收,但是這是所有TCP保證。它不保證數據在單個數據包中發送和接收。您需要收集數據並將它們放在緩衝區中,直到在複製數據之前獲得所需的塊大小。

1

也許讀取的調用沒有讀完整個8字節而返回。我會檢查他們報告他們閱讀的長度。

您可能還會發現valgrind或strace提供信息,以便更好地理解您的代碼爲何如此行事。如果你讀取的是短讀,strace會告訴你係統調用返回的是什麼,valgrind會告訴你,你正在讀取長度變量中未初始化的字節。

1

它在同一臺機器上工作的原因是block_size和block_count是作爲二進制值發送的,當它們被客戶端接收和解釋時,它們具有相同的值。然而,如果兩個通信機器具有不同的用於表示整數的字節順序,例如,如果兩個機器通信的字節順序不同, x86與SPARC或sizeof(int)是不同的,例如, 64位與32位,那麼代碼將無法正常工作。

您需要驗證兩臺機器的sizeof(int)和字節順序是否相同。在服務器端,輸出sizeof(int)和storage-> length和p-> blocksize的值。在客戶端打印出sizeof(int)和block_count和block_size的值。

當它不能正常工作時,我想你會發現它們不一樣。如果這是真的,那麼如果它包含任何二進制數據,那麼數據的內容也將被誤解。