我在C中编写了一个UDP套接字客户端 - 服务器。客户端每秒都向服务器发送一个查询很长一段时间(例如:1周)。 我的代码运行正常,但我可以在时间线上看到内存大幅增加,大约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;
}
}
}
设置params套接字的功能:
void set_param()
{
/** Set client params **/
memset(&local_addr, 0, sizeof(struct sockaddr_in));
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(SRC_PORT);
local_addr.sin_addr.s_addr = inet_addr(SRC_IP);
/** Configure settings in address struct **/
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(DST_PORT);
serverAddr.sin_addr.s_addr = inet_addr(DST_IP);
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
addr_size = sizeof serverAddr;
clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
if ( clientSocket < 0 )
{
error( "Error socket no create" );
exit(1);
}
if (bind(clientSocket, (struct sockaddr *)&local_addr, sizeof(local_addr))< 0)
{
close(clientSocket);
error( "Error bind in socket" );
exit(1);
}
/** Socket create OK**/
cont_parametros = 1;
}
主要部分
int main( int argc, char* argv[] )
{
long long int t1;
char t1_str[20];
while(1)
{
t1=ts();
sprintf(t1_str, "%lld", t1);
consultar_servidor(t1_str);
sleep(1);
}
}
答案 0 :(得分:2)
主要问题是你打电话
close(clientSocket);
代码的所有分支,除非您使用recvfrom
成功阅读数据并从0
返回代码consultar_servidor()
。因此,套接字永远不会关闭,并且存在套接字描述符泄漏。
代码中可能存在其他错误,请确保在valgrind下进行测试。
我建议重新构建代码以避免重复并帮助捕获这些错误。例如,一个选项是将清理代码移动到单独的函数。另一种选择是使用goto
cleanup pattern,除非您对代码中没有goto
感到妄想。
答案 1 :(得分:0)
我没有在发布的代码中看到任何实际的内存分配,因此如果存在直接内存泄漏,则必须由程序中其他位置的问题引起。
正如@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()的所有调用。
然后运行程序,并观察其stdout输出。如果调试输出中打印的数字不断增加,则程序正在泄漏套接字,您需要找出原因/方法并进行修复。如果没有,那么你在其他地方还有其他一些问题。