Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 套接字UDP客户端内存泄漏_C_Sockets_Udp - Fatal编程技术网

C 套接字UDP客户端内存泄漏

C 套接字UDP客户端内存泄漏,c,sockets,udp,C,Sockets,Udp,我用C编写了一个UDP套接字客户端服务器。在很长一段时间内(例如:1周),客户端每秒向服务器发送一个查询。 我的代码运行得很好,但我可以在时间轴上看到ram显著增加,大约14小时后,内存增加到150M左右 增量在客户端,服务器工作正常 我需要检测导致此问题的原因,因为程序将运行很长时间 我的代码出了什么问题 这是我在客户端的代码: int consultar_servidor(char *t1_str_) { struct timeval t_ini, t_fin, tv; do

我用C编写了一个UDP套接字客户端服务器。在很长一段时间内(例如:1周),客户端每秒向服务器发送一个查询。 我的代码运行得很好,但我可以在时间轴上看到ram显著增加,大约14小时后,内存增加到150M左右

增量在客户端,服务器工作正常

我需要检测导致此问题的原因,因为程序将运行很长时间

我的代码出了什么问题

这是我在客户端的代码:

int consultar_servidor(char *t1_str_)
{
    struct timeval t_ini, t_fin, tv;
    double secs;
    char cadena_enviada[67];
    char cadena_recibida[67];
    char tx_str[51]= "|0000000000000000|0000000000000000|0000000000000000";
    int validacion, i;

    long long int t4;
    char t4_str[20];

    char t2_str_rec[20];
    char t2_pps_str_rec[20];

    char t3_str_rec[20];

    int nBytes, numfd;


    if (t1_str_ != 0)
    {
        strcpy(cadena_enviada,t1_str_);
        strcat(cadena_enviada,tx_str);
    }
    else
    {  
        error("Error recepcion t1");
        return 1;
    }   
    if (cont_parametros == 0)
    {
        set_param();
    }

    if ( connect( clientSocket, ( struct sockaddr * ) &serverAddr, sizeof( serverAddr) ) < 0 ) 
        error( "Error connecting socket" ); 

    if ( sendto(clientSocket,cadena_enviada,sizeof(cadena_enviada),0,(struct sockaddr *)&serverAddr,addr_size) < 0)
    {
        close(clientSocket);
        error( "Error sentto function");
        cont_parametros = 0;
        return 1;
    }   

    /** Socket nonblock **/
    int flags = fcntl(clientSocket, F_GETFL, 0);
    fcntl(clientSocket, F_SETFL, flags | O_NONBLOCK);
    fd_set readfds;

    FD_ZERO(&readfds);
    FD_SET(clientSocket, &readfds);
    numfd = clientSocket + 1;   

    /** Set 700us to receive **/
    tv.tv_sec=0;
    tv.tv_usec=700000;  

    /** Server send me **/
    int recibo = select(numfd, &readfds,NULL,NULL,&tv);

    switch (recibo) 
    {
        case -1:
            /** Error reception **/
            error("Error reception");
            FD_CLR(clientSocket, &readfds);
            close(clientSocket);
            cont_parametros=0;
            return 1;
        case 0:
            /** Timeout and close socket **/
            error( "Error timeout" );
            FD_CLR(clientSocket, &readfds);
            close(clientSocket);
            cont_parametros = 0;
            return 1;
        default:
            /** If socket contain data **/
            if (FD_ISSET(clientSocket, &readfds)) 
            {
                /** catch t4 **/
                t4=ts();
                sprintf(t4_str, "%lld", t4);

                /** Receive server message**/
                nBytes = recvfrom(clientSocket,cadena_recibida,sizeof(cadena_recibida),0,NULL, NULL);
                /** If si a bad data **/
                if (nBytes < 0)
                {
                    error( "Error recept data" );
                    FD_CLR(clientSocket, &readfds);
                    close(clientSocket);
                    cont_parametros = 0;
                    return 1;               
                }

                /** Clean  set **/
                FD_CLR(clientSocket, &readfds);

                int i;

                /** trim t2**/
                for(i=17;i<33;i++)  t2_str_rec[i-17]=cadena_recibida[i];
                t2_str_rec[16]= '\0';

                /** trim t3**/
                for(i=34;i<51;i++)  t3_str_rec[i-34]=cadena_recibida[i];
                t3_str_rec[16]= '\0';

                printf("%s|%s|%s|%s\n",t1_str_, t2_str_rec, t3_str_rec, t4_str);
                return 0;
            }   
    }
}

主要问题是你打电话

close(clientSocket);
对于代码的所有分支,除非您使用
recvfrom
成功读取数据,并使用
0
consultar\u servidor()
返回数据。因此,套接字永远不会关闭,并且存在套接字描述符泄漏

代码中可能还有其他错误,请确保在valgrind下对其进行测试


我建议重新构造代码以避免重复,并帮助捕获此类错误。例如,一个选项是将清理代码移动到单独的函数。另一种选择是使用
goto
,除非你偏执于代码中没有
goto

主要问题是你调用

close(clientSocket);
对于代码的所有分支,除非您使用
recvfrom
成功读取数据,并使用
0
consultar\u servidor()
返回数据。因此,套接字永远不会关闭,并且存在套接字描述符泄漏

代码中可能还有其他错误,请确保在valgrind下对其进行测试


我建议重新构造代码以避免重复,并帮助捕获此类错误。例如,一个选项是将清理代码移动到单独的函数。另一种选择是使用
goto
,除非您担心代码中没有
goto

我在发布的代码中看不到任何实际内存分配,因此,如果存在直接内存泄漏,它一定是由程序中其他地方的问题引起的

正如@kfx提到的,另一种可能性是插座泄漏;由于每个套接字都带有缓冲区,这些缓冲区会占用一定数量的RAM,因此也可能会增加内存使用量

测试程序是否泄漏套接字的一种简单方法是在程序中添加如下内容:

static int socketCount = 0;

int debug_socket(int domain, int type, int protocol)
{
   int ret = socket(domain, type, protocol);
   if (ret >= 0)
   {
      ++socketCount;
      printf("After socket() call succeeded, there are now %i sockets in use by this program\n", socketCount);
   }
   else perror("socket() failed!");

   return ret;
}

int debug_close(int sock)
{
   int ret = close(sock);
   if (ret == 0)
   {
      --socketCount;
      printf("After close() call succeeded, there now %i sockets in use by this program\n", socketCount);
   }
   else perror("close() failed!");

   return ret;
}
。。。然后用debug_socket()临时替换程序中对socket()的所有调用,用debug_close()替换程序中对close()的所有调用


然后运行程序,并查看其标准输出。如果调试输出中打印的数字不断增加,则说明程序正在泄漏套接字,您需要找出原因/方法并修复它。如果没有,那么您在其他地方还有一些问题。

我在发布的代码中没有看到任何实际的内存分配,因此,如果存在直接内存泄漏,那么它一定是由程序中其他地方的问题引起的

正如@kfx提到的,另一种可能性是插座泄漏;由于每个套接字都带有缓冲区,这些缓冲区会占用一定数量的RAM,因此也可能会增加内存使用量

测试程序是否泄漏套接字的一种简单方法是在程序中添加如下内容:

static int socketCount = 0;

int debug_socket(int domain, int type, int protocol)
{
   int ret = socket(domain, type, protocol);
   if (ret >= 0)
   {
      ++socketCount;
      printf("After socket() call succeeded, there are now %i sockets in use by this program\n", socketCount);
   }
   else perror("socket() failed!");

   return ret;
}

int debug_close(int sock)
{
   int ret = close(sock);
   if (ret == 0)
   {
      --socketCount;
      printf("After close() call succeeded, there now %i sockets in use by this program\n", socketCount);
   }
   else perror("close() failed!");

   return ret;
}
。。。然后用debug_socket()临时替换程序中对socket()的所有调用,用debug_close()替换程序中对close()的所有调用


然后运行程序,并查看其标准输出。如果调试输出中打印的数字不断增加,则说明程序正在泄漏套接字,您需要找出原因/方法并修复它。如果没有,那么其他地方还有一些问题。

您在哪里分配字符*t1\u str?(您在哪里和如何调用
int consultar\u servidor(char*t1\u str\u)
?现在添加主要部分以完成代码您在哪里分配
char*t1\u str\u
?(您在哪里和如何调用
int consultar\u servidor(char*t1\u str\u)
?现在添加主要部分以完成代码,更不用说
“|0000000000000000 | 0000000000000000 | 0000000000000000”
是52字节,而不是51字节,最大长度值是19个字符,因此整个字符串可能超过67个字符。可能还有其他问题……我需要在没有错误发生时保持套接字打开,这就是不使用close(clientSocket)的原因在recvfrom之后。我这样做是为了避免每次查询都打开和关闭套接字,并节省处理时间。您认为有什么方法可以做到这一点吗?我当时犯了错误,但从您提供的代码中根本不清楚这一点(作为一个说英语的人,很难猜测您从未显示过的明显全局变量
cont_parametros
的含义)。如果您关心性能,为什么每次都要重新连接并取消阻止套接字?这里可能会发生一些有趣的事情,但如果没有更明确的问题,人们将不会主动为您调试代码。或者,可能更简单,您可以始终关闭并重新打开套接字。cont_参数是一个全局变量le,它就像一个确定错误发生时间的标志。现在我要用更简单的方法,关闭并重新打开套接字。几个小时后,我将观察程序的行为并再次对您进行注释。更不用说
“|0000000000000000 | 0000000000000000 | 0000000000000000000000“
是52字节,而不是51字节,最大长度值是19个字符,因此整个字符串可能超过67个字符。可能还有其他问题……我需要在没有错误发生时保持套接字打开,这就是不使用close(clientSocket)的原因。”在recvfrom之后。我这样做是为了避免每次查询都打开和关闭套接字,并节省处理时间。您认为有什么方法可以做到这一点吗?我当时犯了错误,但从您提供的代码中根本不清楚这一点(作为一个说英语的人,很难猜测您从未显示过的明显全局变量
cont_parametros
的含义)。