2014-06-17 130 views
1

寫一個完整緩衝區我想寫write system call在使用TCP套接字充滿BUFF_SIZE字節的緩衝區:使用write()系統調用

#include <unistd.h> 
ssize_t write(int fd, const void *buf, size_t count); 

documentation指出

寫( )將寫入字節,從緩衝器指向的buf計數到文件描述符fd引用的文件。

當然,寫入的實際的字節數可以通過返回值檢測出來。但是,如果我想確保我的整個字節緩衝區通過連接發送,那麼執行此操作的好方法是什麼?到目前爲止,我在想:

while ((ch = fgetc(pipe)) != EOF) 
{ 
    buff[ 0 ] = ch; 
    bytes_in_buff++; 

    // fill a buffer's worth of data from the pipe 
    for (int i = 1; i < BUFF_SIZE; ++i, ++bytes_in_buff) 
    { 
     if ((ch = fgetc(pipe)) == EOF) 
      break; 

     buff[ i ] = ch; 
    } 

    // write that buffer to the pipe 
    int bytes_sent = 0; 
    while (bytes_sent < BUFF_SIZE) 
    { 
     bytes_sent = write(fd, buff, bytes_in_buff); 
    } 
} 

當然不過,一些多餘字節將被髮送,如果我繼續每次bytes_sent < BUFF_SIZE發送整個緩衝區。

回答

1

您需要編輯您給出的寫入參數,以解決已發送的數據問題。因此,像這樣:

int bytes_sent = 0; 
int remaining = BUFF_SIZE; 
while (remaining) 
{ 
    bytes_sent = write(fd, buff, remaining); 
    remaining -= bytes_sent; 
    buff += bytes_sent; 
} 
2

如果write()回報低於BUFF_SIZE您建議的循環不會終止;你需要檢查錯誤。

你需要的東西是這樣的:

while (bytes_sent < BUFF_SIZE) 
{ 
    bytes_sent = write(fd, buff, bytes_in_buff); 
    if (bytes_sent < 0) 
    { 
     perror("write"); // or whatever 
     break; 
    } 
    buff += bytes_sent; 
    bytes_in_buff -= bytes_sent; 
} 

然而這個問題已在新聞討論在extenso:comp.protocols.tcp-IP幾年前,這是地方TCP/IP實現者閒逛,並且在那裏同意,在阻塞模式下,write()send()必須在返回之前發送整個緩衝區。

+0

是您當系統調用被阻塞然後中斷時,最後一段爲真?如果中斷,系統調用的實現是否會自動重啓I/O? – jxh

+0

@jxh對不起,我不記得在那個詳細程度的討論,但在我看來,它不應該重新啓動。它如何建議中斷和在中斷之前傳輸的字節數一直是我的一個謎。 – EJP

2

看一看下面的函數,它繞一圈write()直到s個字節b已經書面或發生了一個致命的錯誤:

int writen(const int sd, const char * b, const size_t s, const int retry_on_interrupt) 
{ 
    size_t n = s; 
    while (0 < n) 
    { 
    ssize_t result = write(sd, b, n); 
    if (-1 == result) 
    { 
     if ((retry_on_interrupt && (errno == EINTR)) || (errno == EWOULDBLOCK) || (errno == EAGAIN)) 
     { 
     continue; 
     } 
     else 
     { 
     break; 
     } 
    } 

    n -= result; 
    b += result; 
    } 

    return (0 < n) ?-1 :0; 
} 

這樣稱呼它:

int retry_on_interrupt = ... /* {0|1} depending on wether a signal reception shall abort the write operation or not. */ 
int result = writen(fd, buff, sizeof(buf), retry_on_interrupt) 
if (-1 == result) 
{ 
    perror("writen()"); 
} 
+0

這真的很清楚。非常感謝。 – ironicaldiction

+0

用'fdopen'轉換爲'FILE *'然後用'fwrite'就足夠了嗎? –