通过libcurl以二进制格式传输的文件已损坏

还有许多其他线程在讨论二进制文件损坏,但是它们似乎都与我的问题无关。

我有一个下载/读取文件的C程序。

因为我没有将获取的所有文件都写到文件中,所以我使用curl的功能是将数据存储到字符串中。以后,我可以自由地将此字符串写入文件,也可以不写入。

我有一个二进制文件。 我把它放在FTP上。

如果我通过filezilla之类的ftp客户端下载它,则其中包含正确的内容(即,当我整理编译后的二进制文件时得到的字符相同) 如果我使用curl命令行下载文件,则该文件也包含正确的内容。

如果我使用程序下载此类文件,则该文件将仅包含类似“ ELF”的字符串,后跟3个不可写/不可读的字符。

请注意,这仅在二进制文件中发生。文本文件已传输/只读文件。 同样重要的是要知道似乎是从curl传递到我的函数的数据已经是错误的:如果将数据的printf放在我的write函数中,我会看到相同的ELF + 3个不可读的chars字符串,因此我以后使用的将其写入文件的方法不是问题。

当我使用详细信息时,curl表示它处于二进制模式,但是二进制文件没有正确传输。

这是我到目前为止所拥有的,对于任何非二进制文件都可以正常工作,否则总是垃圾。预先感谢:

struct string 
{
  char *ptr;
  size_t len;
};

char *usr_psswd(char *user,char *psswd)
{
    char *usrpsswd;

    usrpsswd = (char *)malloc(strlen(user) + strlen(psswd) + 2);
    int i = 0;
    int j = 0;

    while (user[i])
    {
        usrpsswd[i] = user[i];
        ++i;
    }
    usrpsswd[i++] = ':';
    while (psswd[j])
    {
        usrpsswd[i] = psswd[j];
        ++i;
        ++j;
    }
    usrpsswd[i] = 0;
    return usrpsswd;
}

void init_string(struct string *s) 
{
  s->len = 0;
  s->ptr = malloc(s->len+1);
  if (s->ptr == NULL) 
  {
    fprintf(stderr,"malloc() failed\n");
    exit(EXIT_FAILURE);
  }
  s->ptr[0] = '\0';
}

size_t writefunc(void *ptr,size_t size,size_t nmemb,struct string *s)
{
    size_t new_len = s->len + size*nmemb;
    s->ptr = realloc(s->ptr,new_len+1);
    if (s->ptr == NULL) 
    {
        fprintf(stderr,"realloc() failed\n");
        exit(EXIT_FAILURE);
    }
    memcpy(s->ptr+s->len,ptr,size*nmemb);
    s->ptr[new_len] = '\0';
    s->len = new_len;
    return size*nmemb;
}

char *curl_get(char *addr,t_data *data)
{
  CURL *curl;
  CURLcode res;
  char *rtrn;
  curl = curl_easy_init();
  if(curl) 
  {
    struct string s;
    init_string(&s);
    curl_easy_setopt(curl,CURLOPT_URL,addr);
    curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,writefunc);
    curl_easy_setopt(curl,CURLOPT_WRITEDATA,&s);
    curl_easy_setopt(curl,CURLOPT_PORT,21);
    curl_easy_setopt(curl,CURLOPT_USERPWD,usr_psswd(data->login,data->password));
    res = curl_easy_perform(curl);
    if(res != CURLE_OK)
    {
        printf("curl_easy_perform() failed: %s\n",curl_easy_strerror(res));
        free(s.ptr);
        curl_easy_cleanup(curl);
        return NULL;
    }
    rtrn = strdup(s.ptr);
    free(s.ptr);
    curl_easy_cleanup(curl);
  }
  return rtrn;
}
nijiaoshenmene 回答:通过libcurl以二进制格式传输的文件已损坏

您的问题是您将二进制数据视为字符串。

strdup函数的工作原理与任何其他字符串函数一样:查找字符串终止符以查找源字符串的结尾。字符串终止符'\0'是字节值0。因此,如果二进制数据包含任何零字节(很有可能),那么它将被视为“字符串”的结尾。

简单的解决方案?只需return s.ptr;,但请注意,无法使用返回的指针找出数据的长度。因此,更好的解决方案可能是返回s本身(因为它包含指向数据及其大小的指针)。

,

您看到的大多数问题是由于使用了为处理字符串而设计的技术,但已应用于二进制文件。

编写某些时候必须与二进制数据和文件内容一起使用的代码时,最好遵循一些规则

  

1)用于包含二进制数据的变量应该比unsigned char更喜欢char。例如:

char *usr_psswd(char *user,char *psswd){...  

应写为

unsigned char *usr_psswd(unsigned char *user,size_t lenUser,unsigned char *psswd,size_t lenPsswd){...  

注意:下面介绍了包含数组长度的原因。

More on the rational of using unsigned char with binary data

  

2)避免使用字符串函数,例如strdup()strlen()等。编写它们都是为了寻找终止的空字节以指示 {{3} } 。例如:>

usrpsswd = (char *)malloc(strlen(user) + strlen(psswd) + 2);

应写为:

 usrpsswd = malloc(lenUser + lenPasswd + 1);//No need for null terminator. (+1 for delimiter,per comments)
                                        //usrpasswrd should be unsigned char *
                                        //Casting return of malloc not recommended. in C.  

C string

本文链接:https://www.f2er.com/3109655.html

大家都在问