2011-10-23 15 views
0

我創建了一個FIFO,作爲家庭作業,一個大項目,模擬郵箱服務器編寫正確的方式/讀取數據超過

我不能發佈項目,因爲它很大(有很多文件),但我可以說有時我丟失了一些數據,或者它不能保持它的完整性。

我使用這些代碼段來傳輸數據,是不是有點錯Network_IO是我說的功能:

#include "Network.h" 

int Network_Open(const char* path,int oflag) 
{ 
    return open(path,oflag); 
} 

ssize_t Network_IO(int fifo,NetworkOpCodes opcode,void* data,size_t dataSize) 
{ 
    ssize_t retsize = 0; 
    ssize_t tmpDataSize = (ssize_t)dataSize; 
    errno = 0; 

    if (tmpDataSize == 0) return 0; 

    while ((retsize = (opcode == NetworkOpCode_Write? write(fifo,data,tmpDataSize) : read(fifo,data,tmpDataSize))) != tmpDataSize) 
    { 
     if (errno != EINTR) break; 
    } 

    return retsize; 
} 

Boolean Network_Send(int fifo,const void* data,size_t dataSize) 
{ 
    return ((ssize_t)dataSize) == Network_IO(fifo,NetworkOpCode_Write,(void*)data,dataSize); 
} 

Boolean Network_Receive(int fifo,void* data,size_t dataSize) 
{ 
    return ((ssize_t)dataSize) == Network_IO(fifo,NetworkOpCode_Read,data,dataSize); 
} 

Boolean Network_Close(int fifo) 
{ 
    if (fifo >= 0) 
     return close(fifo) == 0; 
} 

編輯1:我使用的實際測試,其代碼段

Boolean Network_IO(int fifo,NetworkOpCodes opcode,void* data,size_t dataSize) 
{ 
    ssize_t retsize = 0; 
    ssize_t tmpDataSize = (ssize_t)dataSize; 
    ssize_t sentDataSize = 0; 
    errno = 0; 

    if (tmpDataSize == 0) return True; 

    while (sentDataSize < tmpDataSize) 
    { 
     switch(opcode) 
     { 
      case NetworkOpCode_Write: 
       retsize = write(fifo,data + sentDataSize,tmpDataSize - sentDataSize); 
       break; 
      case NetworkOpCode_Read: 
       retsize = read(fifo,data + sentDataSize,tmpDataSize - sentDataSize); 
       break; 
     } 
     if (retsize < 0) 
     { 
      if (errno != EINTR) return False; 
      else 
      { 
       errno = 0; 
       continue; 
      } 
     } 
     sentDataSize += retsize; 
    } 

    if (errno != 0) 
     return False; 

    return sentDataSize == tmpDataSize; 
} 

Boolean Network_Send(int fifo,const void* data,size_t dataSize) 
{ 
    return Network_IO(fifo,NetworkOpCode_Write,(void*)data,dataSize); 
} 

Boolean Network_Receive(int fifo,void* data,size_t dataSize) 
{ 
    return Network_IO(fifo,NetworkOpCode_Read,data,dataSize); 
} 

回答

2

恕我直言,Network_IO()函數沒有任何用處。它的唯一目的是爲了解讀由Network_Send()和Network_Receive()函數提供給它的讀/寫調用的操作碼。最好是調用read()並直接在Network_Send()和Network_Receive()函數中寫入。返回類型(布爾)的選擇也很奇怪。

read()和write()的錯誤條件可能不同,將來也許不止EINTR需要在其中一箇中處理。另外:您的功能區塊,這意味着:他們不會返回,直到實際發送或接收到所需的金額。另請注意,對於管道和fifo,內核提供的緩衝空間量非常有限,通常爲1個內存頁。這增加了讀取器或寫入器在讀取或寫入時被阻塞的機會,並且導致每個數據塊傳輸(至少)兩次上下文切換。

「循環直到完成」方法;由Mat提供的是關於做事的標準方式。還要準備讀/寫返回零。

編輯:什麼墊意味着,你需要處理部分讀取/寫入:你需要從開始,你離開,發送/接收緩衝區的其餘部分。這是一個開始:

int mywrite(int fd, char *buff, size_t size) 
{ 
int rc; 
size_t done, todo; 

for (done=0; done < size;) { 
    todo = size - done; 
    rc = write (fd, buff+done, todo); 
    switch (rc) { 
    case -1: /* some read error: check it */ 
     switch(errno) { 
     case EINTR: continue; 
     /* ... maybe some other cases you need to handle */ 
     default: return -1; 
      } 
     break; 
    case 0: /* (in some cases) the other side closed the connection */ 
     /* handle it here; possibly return error */ 
     break; 
    default: /* the normal case */ 
     done += rc; 
     break; 
     } 
    } 
return done; 
} 
+0

中看到代碼片段雖然我覺得你的回答很有趣,但我不需要討論我的設計決定。圍繞這一選擇有很多事情,我不會改變「包裝」寫入/讀取呼叫的決定。此外**阻止**實際上是由教師爲了學習目的而要求的。 –

+1

那麼,案例是你的程序「幾乎是正確的」:看起來你可以編寫和調試一個計算機程序,但不知道要寫什麼。對你的設計選擇的文體評論並不打算作爲評論,而更多的是讓你意識到設計確實很重要。編程是微不足道的,設計程序不是。順便說一句:linux可掛載文件系統通過函數指針來實現你想要的抽象,或多或少的OO。 – wildplasser

+0

設計背後的主要問題是它是一項家庭作業,有些東西應該像「老師說的」一樣完成,特別是循環方法,你可以在老師的筆記中找到它,所以我直接使用它,但是我認爲它不是完全正確,正如Mat所說,我認爲我必須發送數據的「重新部分」,我會試一試。我專注於設計,但是......好吧,我討厭C,並且在寫了很多天之後我生氣了。 –

2

對於write情況下,你的代碼歸結爲

while ((retsize = write(fifo,data,tmpDataSize)) != tmpDataSize) { ... } 

想象一下,在第一個write上,只有一個字節被寫入。如果發生這種情況,您需要下一個write嘗試推動tmpDataSize-1字節,從data+1開始。但是你現在所做的將會重新發送一切,包括第一個字節。

在僞代碼,邏輯應該是這樣的:在讀的情況下

while (bytesLeftToSend > 0) { 
sent = write(fifo, data, bytesLeftToSend); 
if (sent == -1) { 
    // report error and bail out 
} 
bytesLeftToSend -= sent; 
data += sent; 
} 

同樣的事情。

順便說一下,雖然與轉讓和?:構造是真的很難閱讀。

+0

Mh,丟棄「舊」數據和重新發送它們全部(只是問)背後的問題是什麼?有一種情況是,我的寫/讀操作一直髮送0,這很無聊,你知道爲什麼會發生這種情況嗎? –

+0

問題是管道的另一端無法確定您是否重新發送。唯一可能導致應用程序發送大量零的是你的代碼。如果你對你實際發送的數據或者在閱讀過程中如何解開數據感到隨意,可能會發生任何事情。 – Mat

+0

我嘗試了一個類似於你所描述的實現,但目前效果不佳,或者至少我獲得了比平常更多的錯誤。我試圖發現爲什麼,你可以在**編輯1 ** –

相關問題