C 线程和 curl 内存泄漏

标签 c curl memory-leaks valgrind

我无法弄清楚我的代码的奇怪行为。 基本上程序监听一个 tcp 端口,在获得启动/停止命令后,它创建一个 curl 线程并开始下载流。 问题是,每次下载流时,程序都会在共享内存中增长。多次下载后,程序停止运行。 - 它接受开始/停止命令,但只下载一小块数据。我假设,有一些内存泄漏。 代码:

#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <curl/curl.h>



#define MY_PORT         8888
#define MAXBUF          1024
int hour=1,min=1,sec=1,year=0,month=0,mday=0;
int stop=0;
static void daemon();
CURL *curl;
CURLcode res;

size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
     size_t written;
        written = fwrite(ptr, size, nmemb, stream);
        if(stop)
            return -1;
        return written;
}
    void * curl_thread(){

        FILE *fp;
        char format[] = "/root/test/archive_%d-%s-%s_%s.%s.%s.mp3";
        char outfilename[sizeof format+100];
        char mi[3];
        char mth[3];
        char dom[3];
        char hrs[3];
        char secs[3];
        sprintf(mth, "%d", month);
        sprintf(dom, "%d", mday);
        sprintf(hrs, "%d", hour);
        sprintf(mi, "%d", min);
        sprintf(secs, "%d", sec);
        if (month<10){
                sprintf(mth, "0%d", month);}
        if (mday<10){
                sprintf(dom, "0%d", mday); }
            if (hour<10){
                sprintf(hrs, "0%d", hour); }
        if (min<10){
                sprintf(mi, "0%d", min);}
        if (sec<10){
                sprintf(secs, "0%d", sec);}
        sprintf(outfilename,format,year,mth,dom,hrs,mi,secs);
        curl = curl_easy_init();
        if(curl) {
                fp = fopen(outfilename,"wb");
                curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:8000/stream.mp3");
                curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
                curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
                curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
                curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
                curl_easy_setopt(curl, CURLOPT_USERAGENT, "curl capture");
                res = curl_easy_perform(curl);
                curl_easy_cleanup(curl);
                fclose(fp);
        }
        stop=0;
        pthread_exit(0);
}




void time_date(void){
        time_t rawtime; 
        time (&rawtime); 
        struct tm *tm_struct = localtime(&rawtime);
        hour = tm_struct->tm_hour;
        min = tm_struct->tm_min;
        sec=  tm_struct->tm_sec;
        year=tm_struct->tm_year + 1900;
        month=tm_struct->tm_mon + 1;
        mday=tm_struct->tm_mday;
}

void daemon(){
        pid_t mypid;
        FILE *pid;
        mypid=fork();
        if (mypid){
                pid=fopen("acapt.pid","w");
                fprintf(pid,"%i",mypid);
                exit (0);
        }
}


int main(int Count, char *Strings[])
{
    daemon();
    time_date();
    int thread=0;

    int sockfd;
    struct sockaddr_in self;
    char buffer[MAXBUF];
    char buff[MAXBUF];
//---Create streaming socket---*/
    if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
    {
        perror("Socket");
        exit(errno);
    }
///Initialize address/port structure---*/
    bzero(&self, sizeof(self));
    self.sin_family = AF_INET;
    self.sin_port = htons(MY_PORT);
    self.sin_addr.s_addr = INADDR_ANY;//*---Assign a port number to the socket---*/
    if ( bind(sockfd, (struct sockaddr*)&self, sizeof(self)) != 0 )
    {
        perror("socket--bind");
        exit(errno);
}
///*---Make it a "listening socket"---*/
    if ( listen(sockfd, 20) != 0 )
    {
        perror("socket--listen");
        exit(errno);
    }
//*---Forever... ---*/
    while (1)
    {   int clientfd;
        struct sockaddr_in client_addr;
        int addrlen=sizeof(client_addr);
//*---accept a connection (creating a data pipe)---*/
        clientfd = accept(sockfd, (struct sockaddr*)&client_addr,&addrlen);
//*---Echo back anything sent---*/
        recv(clientfd, buffer, MAXBUF, 0);
        if (strcmp(buffer, "start\r\n")==0&&!thread){
                        close(clientfd);
                        sleep(5);
                        time_date();
                        pthread_t tid;
                        pthread_create(&tid,NULL,curl_thread,NULL);
                        thread=1;
        }
        if (strcmp(buffer, "stop\r\n")==0&&thread){         
                        close(clientfd);
                        stop=1;
                        thread=0;
                        curl_global_cleanup();
        }
        memset ( buffer, '\0', MAXBUF );
//*---Close data connection---*/
        close(clientfd);
    }
//---Clean up (should never get here!)---*/
    close(sockfd);
    return 0;
}

一次启动/停止后来自 valgrind 的信息:

HEAP SUMMARY:
     in use at exit: 4,897 bytes in 58 blocks    total heap usage: 2,987 allocs, 2,929 frees, 200,756 bytes allocated    576 bytes in 2 blocks are possibly lost in loss record 16 of 20
    at 0x4C272B8: calloc (vg_replace_malloc.c:566)
    by 0x401128E: _dl_allocate_tls (dl-tls.c:300)
    by 0x4E36483: pthread_create@@GLIBC_2.2.5 (allocatestack.c:580)
    by 0x4016A2: main (in /root/test/testas)    LEAK SUMMARY:
    definitely lost: 0 bytes in 0 blocks
    indirectly lost: 0 bytes in 0 blocks
      possibly lost: 576 bytes in 2 blocks

still reachable: 4,321 bytes in 56 blocks
     suppressed: 0 bytes in 0 blocks
Reachable blocks (those to which a pointer was found) are not shown.
To see them, rerun with: --leak-check=full --show-reachable=yes

 For counts of detected and suppressed errors, rerun with: -v
 ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 12 from 6)

谢谢你的帮助。

最佳答案

这可能不是导致崩溃的原因,但您没有将正确的函数类型传递给 pthread_create()。应该是:

void * curl_thread( void* data )
{
    ...

您也永远不会加入线程,每次创建新线程时都会泄漏资源。调用 pthread_join() 或 pthread_detach()。

关于C 线程和 curl 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26669599/

相关文章:

curl - 使用共享 URL (AuthKey) 通过 API 访问 Google Doc?

c# - 如何在 C#/.NET 中创建内存泄漏

android - Leak Canary 使用 ViewPager2 检测 TabLayout 的内存泄漏

模板函数 <queue> 中的 C++ 内存错误

c - 大O重复检查功能

php - 使用 curl 登录 Twitter

c - 构建一个基本的 shell,更具体地说是使用 execvp()

php - 在 PHP 中使用 data-urlencode 获取请求

计算整个字符串,包括 C 中的空格

c++ - 可以在运行时更改 argv(不是由应用程序本身)