2011-11-30 68 views
1

我正在爲我的網絡類編寫一個簡單的服務器,並且我無法正確地將數據傳輸到客戶端(由教授提供)。服務器寫入套接字但數據未到達客戶端

一旦我完成了所有設置並建立了連接,我就開始讀取文件的塊並將它們寫入套接字,檢查讀取和寫入函數的返回是否匹配。我還保持讀取/寫入的字節總數,並將其與總文件大小(通過stat.st_size)進行比較,它們全部匹配。

無論我多少次請求同一個文件,服務器端的日誌總是有正確的度量標準。客戶偶爾會丟失文件的結尾。實際尺寸與預期尺寸之間的差異從一次調用到下一次調整幾乎是不變的,而且它總是缺少文件的末尾,沒有中間的片斷。到達文件的大小也是512的倍數(塊大小)。

所以,似乎整個區塊的一些數目正在它,然後其餘的都迷路somehow.:w

#define CHUNK_SIZE  512 
/* other definitions */ 

int main() 
{ 
    /* basic server setup: socket(), bind(), listen() ... 
     variable declarations and other setup */ 

    while(1) 
    { 
     int cliSock = accept(srvSock, NULL, NULL); 
     if(cliSock < 0) 
     ; /* handle error */ 

     read(cliSock, filename, FILE_NAME_SIZE - 1); 
     int reqFile = open(filename, O_RDONLY); 
     if(reqFile == -1) 
     ; /* handle error */ 

     struct stat fileStat; 
     fstat(reqFile, &fileStat); 
     int fileSize = fileStat.st_size; 

     int bytesRead, totalBytesRead = 0; 
     char chunk[CHUNK_SIZE]; 
     while((bytesRead = read(reqFile, chunk, CHUNK_SIZE)) > 0) 
     { 
     totalBytesRead += byteasRead; 
     if(write(cliSock, chunk, bytesRead) != bytesRead) 
     { 
      /* perror(...) */ 
      /* print an error to the log file */ 
      bytesRead = -1; 
      break; 
     } 
     } 
     if (bytesRead == -1) 
     { 
     /* perror(...) */ 
     /* print an error to the log file */ 
     close(cliSock); 
     continue; 
     } 

     /* more code to write transfer metrics etc to the log file */ 
    } 
} 

所有拆下的錯誤處理代碼的是打印錯誤消息的一些味道到日誌文件並回到循環的頂部。


編輯擲<本來應該>

+0

如果然後返回0,我們到達了文件的末尾while循環退出('而(0)')和if語句跳過我們在錯誤代碼,我們進入到打印傳輸指標 – Matt

+0

你的困惑可能是由於我錯誤輸入該行上的條件運算符而造成的。老實說,另一種方式根本沒有意義。 – Matt

回答

2

想必你是毫不客氣地用close()關閉套接字時,你寫你想要的插座(或數據或許只是退出的過程中,這做同樣的事情)。

這是不對的 - 如果對方發送了一些你還沒有讀取的數據,連接將被重置。重置會導致未讀數據丟失。

相反,您應該使用shutdown()正常關閉套接字的寫入側,然後等待客戶端關閉。類似:

ssize_t bytesRead; 
char chunk[CHUNK_SIZE]; 

shutdown(cliSock, SHUT_WR); 

while((bytesRead = read(cliSock, chunk, CHUNK_SIZE)) != 0) 
{ 
    if (bytesRead < 0) 
    { 
     if (errno != EINTR) 
     { 
      /* perror() */ 
      /* print error in log file */ 
      break; 
     } 
    } 
    else 
    { 
     /* maybe log data from client */ 
    } 
} 

close(cliSock); 


1.這可以包括EOF,如果對方已關閉了其寫入通道。

+0

我不期望客戶有更多的迴應。客戶端發出服務器讀取的初始請求。只是一個帶有文件名的字符串。服務器在工作目錄中查找文件,然後發送文件。讀取循環完成後,客戶端立即關閉連接。我會嘗試'關閉(cliSock,SHUT_RDWR)'看看是否有所作爲。注意:讀取循環正在讀取本地文件併發送數據,而不是從連接讀取數據。 – Matt

+0

@Matt:使用SHUT_RDWR不會有幫助。這個想法是雙方應該有一個互相聯繫的密切握手。如果客戶端在從服務器端看到EOF後關閉連接,服務器端的SHUT_WR後面的最後一個read()會在這個時候返回0,等待。 – caf

+0

所以這有點像刷新輸出流?我即將坐下來實施它。讓我自己搭上繩子放在樹上:) – Matt

相關問題