高手快救我:如何解决多次调用ping 函数而产生的内存泄漏问题?(问题解决,立即结帖,另加200分)

shuliang 2003-12-30 02:07:43
小妹的监测程序需要不停的调用ping 函数,刚开始调用的几十次没有问题,但当调用的次数上百次后竟出现比较大的内存泄漏(我对ping的原理不怎么懂,是不是里面有缓冲区,满了后开始泄漏?),我的ping 函数是由 MSDN 中的例子改写的,调用方法为:
int judge=nPing(IP) 查了两天两夜,无法解决,老板催得紧,小妹今年刚毕业,经验不足,怕丢饭碗,所以恳请各位大哥大姐们帮忙!!!
不胜感激!!!(若哪位有其他得ping 函数请给我一份:qingyin1019@tom.com

#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#define ICMP_ECHO 8
#define ICMP_ECHOREPLY 0

#define ICMP_MIN 8 // minimum 8 byte icmp packet (just header)

/* The IP header */
typedef struct iphdr {
unsigned int h_len:4; // length of the header
unsigned int version:4; // Version of IP
unsigned char tos; // Type of service
unsigned short total_len; // total length of the packet
unsigned short ident; // unique identifier
unsigned short frag_and_flags; // flags
unsigned char ttl;
unsigned char proto; // protocol (TCP, UDP etc)
unsigned short checksum; // IP checksum

unsigned int sourceIP;
unsigned int destIP;

}IpHeader;

//
// ICMP header
//
typedef struct _ihdr {
BYTE i_type;
BYTE i_code; /* type sub code */
USHORT i_cksum;
USHORT i_id;
USHORT i_seq;
/* This is not the std header, but we reserve space for time */
ULONG timestamp;
}IcmpHeader;

#define STATUS_FAILED 0xFFFF
#define DEF_PACKET_SIZE 32
#define MAX_PACKET 1024

#define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s))
#define xfree(p) HeapFree (GetProcessHeap(),0,(p))
void decode_resp(char *,int ,struct sockaddr_in *);

void fill_icmp_data(char * icmp_data, int datasize)
{
IcmpHeader *icmp_hdr;
char *datapart;
icmp_hdr = (IcmpHeader *)icmp_data;
icmp_hdr->i_type = ICMP_ECHO;
icmp_hdr->i_code = 0;
icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
icmp_hdr->i_cksum = 0;
icmp_hdr->i_seq = 0;
datapart = icmp_data + sizeof(IcmpHeader);
//
// Place some junk in the buffer.
//
memset(datapart,'E', datasize - sizeof(IcmpHeader));
}

USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=0;

while(size >1)
{
cksum+=*buffer++;
size -=sizeof(USHORT);
}
if(size)
{
cksum += *(UCHAR*)buffer;
}
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum);
}

int WaitForEchoReply(SOCKET s)
{
struct timeval Timeout;
fd_set readfds;

readfds.fd_count = 1;
readfds.fd_array[0] = s;
Timeout.tv_sec = 1;
Timeout.tv_usec = 0;
return(select(1, &readfds, NULL, NULL, &Timeout));
}



int nPing(const char * strip)
{
WSADATA wsaData;
SOCKET sockRaw;
struct sockaddr_in dest;
int bread,datasize;
int timeout = 1000;
char *dest_ip;
char *icmp_data;
unsigned int addr=0;
USHORT seq_no = 0;
int nAddrlen = sizeof(struct sockaddr_in);
int nRet;
char *recvbuf;

if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0)
{
return 2;
}

sockRaw = WSASocket (AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL, 0,0);
if (sockRaw == INVALID_SOCKET)
{
return 2;
}
bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));
if(bread == SOCKET_ERROR)
{
return 2;
}
timeout = 1000;
bread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout));
if(bread == SOCKET_ERROR)
{
return 2;
}
memset(&dest,0,sizeof(dest));
addr = inet_addr(strip);
if (addr == INADDR_NONE)
{
return 2;
}
dest.sin_addr.s_addr = addr;
dest.sin_family = AF_INET;
dest_ip = inet_ntoa(dest.sin_addr);
datasize = DEF_PACKET_SIZE;
datasize += sizeof(IcmpHeader);
icmp_data = (char *)xmalloc(MAX_PACKET);
recvbuf = (char *)xmalloc(MAX_PACKET);
if (!icmp_data || !recvbuf)
{
xfree(icmp_data);
xfree(recvbuf);
return 2;
}
memset(icmp_data,0,MAX_PACKET);
fill_icmp_data(icmp_data,datasize);
((IcmpHeader*)icmp_data)->i_cksum = 0;
((IcmpHeader*)icmp_data)->timestamp = GetTickCount();
((IcmpHeader*)icmp_data)->i_seq = seq_no++;
((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data,datasize);

bread = sendto(sockRaw, icmp_data, datasize,0,(struct sockaddr*)&dest,sizeof(dest));
if (bread == SOCKET_ERROR)
{
xfree(icmp_data);
xfree(recvbuf);
return ERR_PING;
}
nRet = WaitForEchoReply(sockRaw);
if(!nRet)
{
xfree(icmp_data);
xfree(recvbuf);
return 1;
}
bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&dest, &nAddrlen);
if (bread == SOCKET_ERROR)
{
xfree(icmp_data);
xfree(recvbuf);
return 1;
}
xfree(icmp_data);
xfree(recvbuf);
return 0;
}
...全文
125 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
zxh7175 2004-02-13
  • 打赏
  • 举报
回复
我帮你改了如下:
#define WIN32_LEAN_AND_MEAN
#define ERR_BEFORE_PING 2
#define ERR_PING 1
#define API_OK 0

#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#define ICMP_ECHO 8
#define ICMP_ECHOREPLY 0

#define ICMP_MIN 8 // minimum 8 byte icmp packet (just header)

/* The IP header */
typedef struct iphdr {
unsigned int h_len:4; // length of the header
unsigned int version:4; // Version of IP
unsigned char tos; // Type of service
unsigned short total_len; // total length of the packet
unsigned short ident; // unique identifier
unsigned short frag_and_flags; // flags
unsigned char ttl;
unsigned char proto; // protocol (TCP, UDP etc)
unsigned short checksum; // IP checksum

unsigned int sourceIP;
unsigned int destIP;

}IpHeader;

//
// ICMP header
//
typedef struct _ihdr {
BYTE i_type;
BYTE i_code; /* type sub code */
USHORT i_cksum;
USHORT i_id;
USHORT i_seq;
/* This is not the std header, but we reserve space for time */
ULONG timestamp;
}IcmpHeader;

#define STATUS_FAILED 0xFFFF
#define DEF_PACKET_SIZE 32
#define MAX_PACKET 1024

//#define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s))
//#define xfree(p) HeapFree (GetProcessHeap(),0,(p))
void decode_resp(char *,int ,struct sockaddr_in *);

void fill_icmp_data(char * icmp_data, int datasize)
{
IcmpHeader *icmp_hdr;
char *datapart;
icmp_hdr = (IcmpHeader *)icmp_data;
icmp_hdr->i_type = ICMP_ECHO;
icmp_hdr->i_code = 0;
icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
icmp_hdr->i_cksum = 0;
icmp_hdr->i_seq = 0;
datapart = icmp_data + sizeof(IcmpHeader);
//
// Place some junk in the buffer.
//
memset(datapart,'E', datasize - sizeof(IcmpHeader));
}

USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=0;

while(size >1)
{
cksum+=*buffer++;
size -=sizeof(USHORT);
}
if(size)
{
cksum += *(UCHAR*)buffer;
}
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum);
}

int WaitForEchoReply(SOCKET s)
{
struct timeval Timeout;
fd_set readfds;

readfds.fd_count = 1;
readfds.fd_array[0] = s;
Timeout.tv_sec = 1;
Timeout.tv_usec = 0;
return(select(1, &readfds, NULL, NULL, &Timeout));
}



int nPing(const char * strip)
{
WSADATA wsaData;
SOCKET sockRaw;
struct sockaddr_in dest;
int bread,datasize;
int timeout = 1000;
char *dest_ip;

unsigned int addr=0;
USHORT seq_no = 0;
int nAddrlen = sizeof(struct sockaddr_in);
int nRet;

char recvbuf[MAX_PACKET];
char icmp_data[MAX_PACKET];
int nCloseResult;

if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0)
{
return ERR_BEFORE_PING;
}

sockRaw = WSASocket (AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL, 0,0);
if (sockRaw == INVALID_SOCKET)
{
return ERR_BEFORE_PING;
}
bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));
if(bread == SOCKET_ERROR)
goto ERROR_PROCESS;

timeout = 1000;
bread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout));
if(bread == SOCKET_ERROR)
goto ERROR_PROCESS;

memset(&dest,0,sizeof(dest));
addr = inet_addr(strip);
if (addr == INADDR_NONE)
goto ERROR_PROCESS;

dest.sin_addr.s_addr = addr;
dest.sin_family = AF_INET;
dest_ip = inet_ntoa(dest.sin_addr);
datasize = DEF_PACKET_SIZE;
datasize += sizeof(IcmpHeader);

memset(icmp_data,0,MAX_PACKET);
fill_icmp_data(icmp_data,datasize);
((IcmpHeader*)icmp_data)->i_cksum = 0;
((IcmpHeader*)icmp_data)->timestamp = GetTickCount();
((IcmpHeader*)icmp_data)->i_seq = seq_no++;
((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data,datasize);

bread = sendto(sockRaw, icmp_data, datasize,0,(struct sockaddr*)&dest,sizeof(dest));
if (bread == SOCKET_ERROR)
goto ERROR_PROCESS;

nRet = WaitForEchoReply(sockRaw);
if(!nRet)
goto ERROR_PROCESS;

bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&dest,
&nAddrlen);
if (bread == SOCKET_ERROR)
goto ERROR_PROCESS;

nCloseResult = closesocket(sockRaw);
if (nCloseResult == SOCKET_ERROR)
{
return ERR_PING;
}
return API_OK;

ERROR_PROCESS:
nCloseResult = closesocket(sockRaw);
if (nCloseResult == SOCKET_ERROR)
{
return ERR_PING;
}
return ERR_PING;
}
tleon 2003-12-31
  • 打赏
  • 举报
回复
因为你创建的socket没有关闭

要关闭socket,请使用以下语句:

shutdown(socket,2) //如果关闭连接,这句必须要
closesocket(socket)


其二,你WSAStartup后没有清除

调用以下语句:
WSACleanup()
jawibn 2003-12-31
  • 打赏
  • 举报
回复
各位真都是细心人!
broadoceans(broadoceans) 一说, 我一看就疑惑了,unsigned int h_len:4真是直觉不出来这样的呢,如果微软这样写的话,也够奇怪,呵呵,莫非有什么原理?各位都说得清楚了,就closesocket和WSACleanup了。
tleon 2003-12-31
  • 打赏
  • 举报
回复
可能是为以后升级方便,现在是IPV4,最新标准IPV6,个人观点

broadoceans 2003-12-30
  • 打赏
  • 举报
回复
你的IPHeader定义不好
typedef struct iphdr {
unsigned int h_len:4; // length of the header
// 最好改为:unsigned char h_len:4
unsigned int version:4; // Version of IP
// 最好改为: unsigned char version:4;
unsigned char tos; // Type of service
unsigned short total_len; // total length of the packet
unsigned short ident; // unique identifier
unsigned short frag_and_flags; // flags
unsigned char ttl;
unsigned char proto; // protocol (TCP, UDP etc)
unsigned short checksum; // IP checksum

unsigned int sourceIP;
unsigned int destIP;

}IpHeader;

原因为:
int 为32位,虽然你只用16位,但是剩余的16位被怕pass掉,
你分析的时候就出错了。我以前自定义IP头的Raw socket就是
因为这一点发送时总出错。
broadoceans 2003-12-30
  • 打赏
  • 举报
回复
不好意思,上面的程序有点错误。
应该将
WSACleanup();
closesocket(sockRaw);
顺序颠倒。
broadoceans 2003-12-30
  • 打赏
  • 举报
回复
改后如下:
int nPing(const char * strip)
{
WSADATA wsaData;
SOCKET sockRaw;
struct sockaddr_in dest;
int bread,datasize;
int timeout = 1000;
char *dest_ip;
char *icmp_data;
unsigned int addr=0;
USHORT seq_no = 0;
int nAddrlen = sizeof(struct sockaddr_in);
int nRet;
char *recvbuf;

if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0)
{
return 2;
}

sockRaw = WSASocket (AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL, 0,0);
if (sockRaw == INVALID_SOCKET)
{

WSACleanup();
return 2;
}
bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));
if(bread == SOCKET_ERROR)
{
WSACleanup();
closesocket(sockRaw);
return 2;
}
timeout = 1000;
bread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout));
if(bread == SOCKET_ERROR)
{
WSACleanup();
closesocket(sockRaw);
return 2;
}
memset(&dest,0,sizeof(dest));
addr = inet_addr(strip);
if (addr == INADDR_NONE)
{
WSACleanup();
closesocket(sockRaw);
return 2;
}
dest.sin_addr.s_addr = addr;
dest.sin_family = AF_INET;
dest_ip = inet_ntoa(dest.sin_addr);
datasize = DEF_PACKET_SIZE;
datasize += sizeof(IcmpHeader);
icmp_data = (char *)xmalloc(MAX_PACKET);
recvbuf = (char *)xmalloc(MAX_PACKET);
if (!icmp_data || !recvbuf)
{
xfree(icmp_data);
xfree(recvbuf);
WSACleanup();
closesocket(sockRaw);
return 2;
}
memset(icmp_data,0,MAX_PACKET);
fill_icmp_data(icmp_data,datasize);
((IcmpHeader*)icmp_data)->i_cksum = 0;
((IcmpHeader*)icmp_data)->timestamp = GetTickCount();
((IcmpHeader*)icmp_data)->i_seq = seq_no++;
((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data,datasize);

bread = sendto(sockRaw, icmp_data, datasize,0,(struct sockaddr*)&dest,sizeof(dest));
if (bread == SOCKET_ERROR)
{
xfree(icmp_data);
xfree(recvbuf);
WSACleanup();
closesocket(sockRaw);
return ERR_PING;
}
nRet = WaitForEchoReply(sockRaw);
if(!nRet)
{
xfree(icmp_data);
xfree(recvbuf);
WSACleanup();
closesocket(sockRaw);
return 1;
}
bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&dest, &nAddrlen);
if (bread == SOCKET_ERROR)
{
xfree(icmp_data);
xfree(recvbuf);
WSACleanup();
closesocket(sockRaw);
return 1;
}
xfree(icmp_data);
xfree(recvbuf);
WSACleanup();
closesocket(sockRaw);
return 0;
}
jawibn 2003-12-30
  • 打赏
  • 举报
回复
各位,有没有什么好的检查内存泄漏的工具呀?
yintongshun 2003-12-30
  • 打赏
  • 举报
回复
closesocket(sockRaw);
broadoceans 2003-12-30
  • 打赏
  • 举报
回复
还有,你没有closesocket
在每次错误返回及最后加上
closesocket(sockRaw);
broadoceans 2003-12-30
  • 打赏
  • 举报
回复
以上就是你内存泄漏的原因。
broadoceans 2003-12-30
  • 打赏
  • 举报
回复
每次WSAStartup()
if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0)
{
return 2;
}
没有WSACleanup()
在每次错误返回及最后加上
WSACleanup()

jawibn 2003-12-30
  • 打赏
  • 举报
回复
怎么没有main给出来呀?

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧