C - 在 while 循环中直接写入数组,同时使用 recv 接收数据

标签 c arrays fopen recv

这是我的代码:

FILE *responseStorage = fopen("response", "w");

if(responseStorage == NULL){
    //error handling
}

int receivedTotal = 0;
while(1){
    ssize_t received = recv(sockfd, buf, BUFSIZ, 0);
    if( received == -1 ){
        //error handling
    }
    if( received == 0 ){
        //end of stream
        break;
    }
    receivedTotal += received;
    if(fwrite(buf, received, 1, responseStorage) != 1){
         //error handling
    }
    memset(buf, '\0', sizeof(buf));
}

fclose(responseStorage);

FILE *responseFile = fopen("response", "r");
char responseArray[receivedTotal];
if(fread(responseArray, receivedTotal, 1, responseFile) == 0){
   //error
}

我正在调用ssize_t returned = recv(sockfd, buf, BUFSIZ, 0);,从服务器接收数据,将我收到的数据保存在receivedTotal += returned; 并使用 fwrite(buf, returned, 1, responseStorage) 将该数据写入我的文件 FILE *responseStorage。之后,在流循环结束时,我以 r 模式打开 responseStorage 文件,创建一个大小为 receivedTotal, 的数组>char responseArray[receivedTotal];,并使用 fread(responseArray, receiveTotal, 1, responseFile 将数据从 responeStorage 文件写入 responseArray.

有没有办法直接写入responseArray?我必须稍后验证响应,所以我需要它在一个数组中。我知道我必须使用 malloc 动态分配数组空间。我想避免使用 receivedTotalresponseStorage

最佳答案

您已经从套接字读取 buf ,所以你所要做的就是写 buf动态分配的字符串而不是 responseStorage 。就像你说的,你只有处理内存空间来适应你的响应。

执行此操作的低效但非常简单的方法是在每次读取时重新分配存储。您可以为先前响应读取的总和以及 buf 中的新字符串分配存储空间。 ,然后将两个字符串写入新分配的空间。您知道这些字符串的长度总和 +1 为空字节,因此您不必太担心可用的分配空间。然而,这是相当昂贵的,因为读取会被一遍又一遍地复制。

稍微复杂一点的方法是分配一个可能相当大的主响应字符串缓冲区,跟踪其总分配空间长度并使用 strncat继续连接buf直到它的长度超过响应中的剩余空间,+1(用于终止零字节)。当房间不够时,您可以调用realloc以获得更多内存。 realloc不是很有效(按照 C 标准),因为它可能需要分配不同的空间,复制现有数据,然后返回一个新指针。

如果你想变得更聪明,你可以分配一个大缓冲区,然后发送 read指向缓冲区中下一个可用点的偏移量的指针。您可能仍然需要增加缓冲区,但至少不需要复制它。 buf然后成为你的响应数组。这是我将演示的实现:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char**argv){
  size_t size = 2;
  size_t len  = 0;
  char* fullbuf = malloc(sizeof(char)*size);
  while(1) {
    ssize_t b = read(STDIN_FILENO, fullbuf + len, sizeof(char) * (size - len-1) );
    if( b < 0) {
      perror("Couldn't read from stdin: ");
      exit(2);
    } else if( b == 0 ){
      break;
    }
    if( b + len + 1 >= size) {
      // time to allocate more memory
      size = size * 2;
      fullbuf = realloc(fullbuf, sizeof(char) * size);
      if( fullbuf == NULL ){
        fprintf(stderr, "Couldn't allocate %zd more bytes of memory\n", size);
        exit(1);
      }
    }
    len += b;
  }
  fullbuf[len] = '\0'; //terminating null space
  printf("%s", fullbuf);
}

在这个演示中,我从标准输入而不是套接字读取,但想法相同。我只阅读了 buf 中可用的数据。 。当它已满(但终止字节)时,我将其空间加倍。请注意,我设置了 fullbuf到 realloc 的输出 - 它可能是相同的地址,也可能不是。

为了证明它有效,我从相当疯狂的 2 字节缓冲区开始,然后从那里加倍,所以有很多 realloc来电。我抓取了 32k 的 lorem ipsum 作为输入。

$ du -h file.txt
 32K    file.txt
$ shasum -a 256 file.txt
346f2adbd1fdca6bf3b03fb0a4d2fd0030e3363e9a9c5d1e22747e1bcc316e37  file.txt
$ ./t  < file.txt | shasum -a 256
346f2adbd1fdca6bf3b03fb0a4d2fd0030e3363e9a9c5d1e22747e1bcc316e37  -

太棒了,如果 shasum 相同,那就意味着我输出了 file.txt确切地。

关于C - 在 while 循环中直接写入数组,同时使用 recv 接收数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58892484/

相关文章:

c - 每个 winapi 函数的 GetLastError() 错误代码列表

java - 我可以将数组作为参数传递给 Java 中具有可变参数的方法吗?

带有 "wb"的 PHP fopen() 不起作用

C语言编程问题

c++ - C/C++ 中的语法糖

c - 从 C 中的单个格式化键盘行填充数组

python - Numpy 的 vstack 是否创建一个新数组 - 它组合的数组的副本?

c++ - fopen mlock 访问冲突

c - 如何以简单的方式在 C 中编辑文本文件?

c - 未对齐的内存访问是否总是导致总线错误?