2015-03-13 40 views
1

我正在使用write(man 2寫入)將數據寫入具有已建立的阻塞和非常慢的TCP連接的套接字。我正在寫大量的數據。 write返回寫入的實際大小,當然它並不是所有的數據都是由於(可能)這個問題的範圍之外的原因而被寫入的。如何確定寫入(2)已將所有數據寫入套接字/文件描述符?

可以肯定的,我封裝我寫的呼叫在一個小圈是這樣的:

do { 
    ssize_t ret = write(client, p, count); 
    if (ret <= 0) 
     break; 
    p += ret; 
    count -= ret; 
} while (count); 

if (count != 0) 
    return -ENODEV; 

有沒有更好的方式來做到這一點,喜歡上了文件描述符設置一個標誌,因而有下層處理呢?

+0

http://stackoverflow.com/a/27623860/1606345 – 2015-03-13 08:14:30

+0

相關:http://stackoverflow.com/a/ 24260280/694576 – alk 2015-03-13 11:42:20

回答

1
size_t done; 
ssize_t ret; 

for (done = 0; done < size; done += ret) { 
    ret = write(client, buff + done, size-done); 

    if (ret == 0) return -ENODEV; 
    if (ret == -1 && errno == EINTR) { ret = 0; continue; } 
    if (ret == -1) return -errno; 
} 
+0

不是我的投票!你的答案更加緊湊,不會修改'p'和'size'。我會相應地編輯我的。 – chqrlie 2015-03-14 14:43:59

+0

我不抱怨downvotes,也不明白它。我認爲在一個循環中保持兩個變量,當只需要一個變量時,通常是一個壞習慣。 – wildplasser 2015-03-14 15:06:56

6

我建議使用while循環而不是do {} whilecount == 0的情況下具有一致的行爲。此外,一些失敗的案例並不錯誤:

while (count > 0) { 
    ssize_t ret = write(client, p, count); 
    if (ret <= 0) { 
     if (ret == 0) 
      return -ENODEV; 
     if (errno == EINTR) 
      continue; 
     else 
      return -errno; 
    }  
    p += ret; 
    count -= ret; 
} 

EINTR如果被寫入任何數據之前的系統調用被中斷signal設置。案件中應該重新啓動write。如果client句柄設置爲非阻塞,則還應該處理EAGAINEWOULDBLOCK

從wildplasser的回答得出一個更爲簡潔和優雅的版本:

for (size_t done = 0; done < count;) { 
    ssize_t ret = write(client, p + done, count - done); 

    if (ret == 0) return -ENODEV; 
    if (ret < 0 && errno != EINTR) return -errno; 
    done += ret; 
} 
+0

'ret'變量具有循環範圍。我不得不把它從循環中提出來。 – wildplasser 2015-03-14 15:07:59

+0

你說得對,我的不好。太糟糕了,我不能在循環範圍聲明它,因爲臭名昭着的'ssize_t' kludge。從循環中提升很糟糕,但將增量移動到'for'主體的末尾也是如此。我會連續選擇後者。 – chqrlie 2015-03-14 22:28:21

+0

因此,最後,你最終得到我的解決方案(除了fot for()循環)和+5而不是-1個學分)我休息我的情況。所以它去... – wildplasser 2015-03-15 00:23:32