从recv中返回填充二进制数据的缓冲区

时间:2012-08-27 19:05:51

标签: c sockets binary recv tmp

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

我目前正在这样做的方法是让它写入缓冲区(基于recv中的content-length字段)写一个临时文件,然后返回该临时文件的名称,这样我就可以将tmp文件读入记忆。

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

或者我最好还是坚持使用tmp文件?

3 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分: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 );

答案 2 :(得分:1)

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

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

避免这种情况的一个好方法是使用像http://apr.apache.org/ APR Commons这样的东西 - 即apr_socket_recv()和相关的内存管理(http://apr.apache.org/docs/apr/1.4/group_ < EM>的apr _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;
}