工具:VC6.0
环境: WIN XP
主要功能:
输入远程主机的IP或者域名,输入ping的次数,点击ping,即可显示ping的结果,且自动将结果记录在日志文件ping_log.txt里。
主要代码如下:
void CPingDlg::OnPing()
{
// TODO: Add your control notification handler code here
WSADATA wsaData;
SOCKET sockRaw;
srand(time(NULL));
CString szDestHost,str,strErr,c_Count;
struct sockaddr_in dest,from;
char recvbuf[100],f_name[100];
hostent* destIp;
int fromlen = sizeof(from);
int timeout = 1000,nLength,i; //超时时间为1秒
UpdateWindow();//重绘窗口,避免残余信息留在编辑框里
m_Edit1.GetWindowText(szDestHost); //GetWindowText
m_Count.GetWindowText(c_Count);
//次数输入有效性检测
for(int j=0;j<c_Count.GetLength();j++)
{
if((int)c_Count[j]<48||(int)c_Count[j]>57)
{
MessageBox("次数输入错误!",NULL,MB_OK);
return;
}
}
if((i=atoi(c_Count))==0)//如果不输入次数
i=3;//默认ping远程主机3次
if(!IpValid(szDestHost))//ip输入有效性检查
{
return;
}
//WSAStartup完成对WinSocket服务的初始化
//MAKEWORD(2,1)表示请求使用的Socket版本,高位为副版本,低位为主版本,wsaData保存返回请求的Socket版本信息
if(WSAStartup(MAKEWORD(2,1),&wsaData))
{
::AfxMessageBox("WINSOCK初始化失败!");
return;
}
sockRaw = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP); //创建套接字,套接字类型为原始套接字
setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO, (char*)&timeout,sizeof(timeout) );//设置套接字状态,限制接收时限
memset(&dest,0,sizeof(dest));
//判断输入的是IP还是域名
if(ipFlag==1)//ipFlag为1是域名,为0是IP
{
if(!(destIp=gethostbyname(szDestHost)))//获得域名主机结构
{
::AfxMessageBox("域名解析失败!");
return;
}
dest.sin_addr.s_addr= inet_addr(inet_ntoa(*(in_addr*)*destIp->h_addr_list));
}
else
{
dest.sin_addr.s_addr= inet_addr(szDestHost);
}
m_Edit2.SetWindowText("--------------Ping开始:----------------\r\n");
dest.sin_family = AF_INET;
dest.sin_port=rand()%1024; //随机端口
char *icmp_data=new char[10];
memset(icmp_data,0,sizeof(icmp_data));//清空分配到的空间
((IcmpHeader*)icmp_data)->i_type = 8; //为8表示回送请求
((IcmpHeader*)icmp_data)->i_code = 0;
((IcmpHeader*)icmp_data)->i_id = (u_short)GetCurrentProcessId(); //获得进程ID作为ICMP的ID号
((IcmpHeader*)icmp_data)->i_seq = 0; //序号
gethostname(f_name,100);//获取本地主机名
//fromIp=gethostbyname(f_name);//获得本地主机结构
for(int k=0;k<i;k++)
{
((IcmpHeader*)icmp_data)->i_cksum = 0;//初始化ICMP的效验码为0
((IcmpHeader*)icmp_data)->i_cksum = in_cksum((u_short *)icmp_data, 8);//计算效验码
sendto(sockRaw,icmp_data,8,0,(struct sockaddr*)&dest,sizeof(dest));//使用指定的套接字发送字节流数据到指定地址
int bread=recvfrom(sockRaw,recvbuf,100,0,(struct sockaddr*)&from, &fromlen);//接收数据
if (bread == SOCKET_ERROR){//接收数据失败
strErr.Format("第%d次尝试ping主机%s失败:错误 %ld...\r\n",
k+1,
szDestHost,
WSAGetLastError()//错误码
);
nLength=m_Edit2.SendMessage(WM_GETTEXTLENGTH);//追加显示到编辑框里
m_Edit2.SetSel(nLength,nLength);
m_Edit2.ReplaceSel(strErr);
continue;
}
else{
Sleep(1000);//显示太快了,停顿一下
str.Format("第%d次尝试ping主机%s[%s]成功:正在使用 %d 字节的数据 PING主机 %s[from:%s] 的端口 %d...\r\n",
k+1,
szDestHost,
ipFlag?inet_ntoa(*(in_addr*)*destIp->h_addr_list):szDestHost,//判断如果是域名则输出域名转换后的IP,否则直接输出IP
strlen(icmp_data),
ipFlag?inet_ntoa(*(in_addr*)*destIp->h_addr_list):szDestHost,
f_name,
//inet_ntoa(*(in_addr*)*fromIp->h_addr_list),//显示本机IP
dest.sin_port
);
nLength=m_Edit2.SendMessage(WM_GETTEXTLENGTH);//实现编辑框控件内容的追加显示
m_Edit2.SetSel(nLength,nLength);
m_Edit2.ReplaceSel(str);
((IcmpHeader*)icmp_data)->i_seq ++;//序号增加,以便再次发送数据
continue;
}
}
closesocket (sockRaw);
WSACleanup();
nLength=m_Edit2.SendMessage(WM_GETTEXTLENGTH);
m_Edit2.SetSel(nLength,nLength);
m_Edit2.ReplaceSel("--------------Ping完成!----------------\r\n");
//保存日志
CFile l_file;
CTime time;
if(!l_file.Open("ping_log.txt",CFile::modeCreate|CFile::modeNoTruncate|CFile::modeWrite)){
MessageBox("打开/创建文件失败!!!");
return;
}
else{
l_file.SeekToEnd();//在原有的文件末尾添加日志信息
m_Edit2.GetWindowText(str);//抓取编辑框显示的信息
str=(time.GetCurrentTime()).Format("%Y年%m月%d日 %H时%M分%S秒")+"\r\n"+str;//日期时间格式控制
str="log记录时间:"+str;//记录日志时间
try
{
l_file.Write(str,str.GetLength());
}
catch(CFileException e)
{
MessageBox("写入文件失败!!!");
}
}
}