2

假设我有一个函数可以轻松地用二进制数据填充缓冲区,我怎样才能使该函数返回所述缓冲区以供进一步使用?

我目前这样做的方式是让它写入缓冲区(基于recv的内容长度字段)写入一个临时文件,然后返回该临时文件的名称,这样我就可以将tmp文件读入内存。

但是,如果我可以直接返回数据而不是将其写入 tmp 文件并使用它,那就太好了。唯一的问题是,如果我返回二进制数据,我无法知道缓冲区的大小(它不是静态的)所以我的问题是:是否有一种方法可以返回这个二进制数据以及它的大小,或者我有什么办法可以使用它?

还是我最好的选择只是坚持使用 tmp 文件?

4

3 回答 3

2

您可以使用与 socket recv 相同的 API。调用者提供缓冲区和最大长度,函数返回实际接收长度。

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

于 2012-08-27T19:11:19.527 回答
1

在 C 中,您可以使用 astruct将一堆数据项封装在一起,然后将其传递给您的函数,例如:

/* 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 );
于 2012-08-27T19:20:31.673 回答
1

嗯 - 临时文件的优点确实是 - 更简单的内存管理。在许多成熟/现代的操作系统上 - 像 /tmp 这样的短期文件的开销非常小(而且你作为开发人员的时间很昂贵)。如果您对文件大小有某种想法 - 一种非常常见的方法如下所示。

但究竟你想要什么取决于内存管理。而且很容易重新发明轮子。

避免这种情况的一个好方法是使用类似http://apr.apache.org/ APR Commons - 即 apr_socket_recv() 和相关的内存管理 (http://apr.apache.org/docs/apr/1.4/ group_ apr _network__io.html#gaa6ee00191f197f64b5a5409f4aff53d1)。一般来说,这是一个长期的胜利。

德。

// 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;
}
于 2012-08-27T19:29:06.683 回答