2012-08-27 83 views
2

假設我有一個函數可以很容易地用二進制數據填充一個緩衝區,我該如何讓該函數返回所說的緩衝區以備後用?返回緩衝區充滿二進制數據recv

我現在正在做的方式是讓它寫緩衝區(基於recv的內容長度字段)寫一個臨時文件,然後返回該臨時文件的名稱,以便我可以讀取tmp文件進入記憶。

這將是很好,但如果我可以直接返回數據,而不是寫入一個tmp文件,並使用它。唯一的問題是,如果我返回二進制數據,我無法知道緩衝區的大小(它不是靜態的)所以我的問題是:是否有返回此二進制數據的方法以及它的大小,或者任何我可以使用它的方式?

或者是我最好的選擇只是堅持使用tmp文件?

+0

您需要展示更多代碼。 – unwind

回答

1

在C語言中,你可以使用一個struct封裝一堆數據項一起,並傳遞給你的功能,如:

/* Describes single I/O buffer */ 
struct buf { 
    char* data; /* pointer to dynamically allocated memory */ 
    size_t mem_size; /* allocation size */ 
    size_t data_len; /* how much data is in the buffer */ 
    struct buf* next; /* can be used for buffer chaining */ 
}; 

/* Returns 0 on success, -1 on error */ 
int read_data(int sockfd, struct buf* pb); 

或者利用價值回報的參數,如:

/* buffer receives data, len tells buffer length on input, and 
* how much was read on success. */ 
int read_data(int sockfd, char* buffer, size_t* len); 
+0

非常酷,謝謝。 –

2

您可以使用與套接字recv相同的API。調用者提供一個緩衝區和最大長度,函數返回實際接收的長度。

http://linux.die.net/man/2/recv

+0

我喜歡它!謝謝! –

1

那麼 - 臨時文件的優點確實是 - 更簡單的內存管理。在很多成熟/現代的操作系統上 - 像/ tmp這樣的短期文件的開銷很小(而且你的開發人員的時間很貴)。如果你有一些文件大小的想法 - 一個非常常見的方法就像下面這樣。

但是究竟你想要什麼取決於內存管理。而且很容易重新發明車輪。

一個好辦法避免這一點就是使用類似http://apr.apache.org/ APR的共同性 - 即apr_socket_recv()和相關的內存管理(http://apr.apache.org/docs/apr/1.4/group_ 四月 _network__io的.html#gaa6ee00191f197f64b5a5409f4aff53d1)。通常這是一個長期的勝利。

Dw。

// On entry: 
//  buffp - pointer to NULL or a malloced buffer. 
//  lenp - pointer for the length; set to 0 or the length of the malloced buffer. 
// On exit 
//  return value < 0 for a fault, 0 for a connection close and > 0 for 
//  the number of bytes read. 
//  buffp will be filled out with the buffer filled; lenleftp with the bytes left 
//  (i.e not yet used). 
//  If post call *buffp != NULL you need to release/clean memory. 
// 
ssize_t sockread(..., unsigned char * * buffp , ssize_t * lenleftp) { 
     if (!buffp || !lenleftp) 
      return -1; // invalid params 

     // claim memory as needed. 
     if (*buffp == 0) { 
      *lenleftp = 16K; 
      *buffp = malloc(*lenleftp); 
     } 

     if (!*buffp || !*lenleftp) 
      return -2; // invalid params 

     ssize_t used = 0; 
     while(1) { 
     ssize_t l = recv(..., *buffp, *lenleftp - used, ..); 
     if (l < 0) { 
      // ignore transient errors we can retry without much ado. 
      if (errno == EAGAIN || errno == EINTR) 
       continue; 

      free(*buffp); *buffp = *lenleftp = NULL; 

      // report a fail. 
      return -3; 
     } 
     // we simply assume that a TCP close means we're done. 
     if (l == 0) 
      break; 

     used += l; 

     // increase buffer space as/when needed. 
     // 
     if (used >= lenleftp) { 
       *lenleftp += 32K; 
       *buffp = realloc(lenleftp); 
     }; 
    } 

    // we're assuming that a read == 0-- i.e. tcp stream done means 
    // we're done with reading. 
    // 
    *lenleftp -= used; 
    return used; 
}