void CPing::Ping(UINT nRetries,LPCSTR pstrHost,HWND hWnd)
{
SOCKET rawSocket;
LPHOSTENT lpHost;
UINT nLoop;
int nRet;
struct sockaddr_in saDest;
struct sockaddr_in saSrc;
DWORD dwTimeSent;
DWORD dwElapsed;
u_char cTTL; m_hWnd = hWnd; CString str; ASSERT(IsWindow(hWnd));
// Create a Raw socket
rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (rawSocket == SOCKET_ERROR)
{
WSAError("socket()");
return;
}
// Lookup host
lpHost = gethostbyname(pstrHost);
if (lpHost == NULL)
{
str.Format("Host not found: %s", pstrHost);
::PostMessage(m_hWnd,WM_MSG_STATUS, 0, (LPARAM) AllocBuffer(str));
::PostMessage(m_hWnd,WM_PING_END, 0, 0);
return;
}
// Setup destination socket address
saDest.sin_addr.s_addr = *((u_long FAR *) (lpHost->h_addr));
saDest.sin_family = AF_INET;
saDest.sin_port = 0; // Tell the user what we're doing
str.Format("Pinging %s [%s] with %d bytes of data:",
pstrHost,
inet_ntoa(saDest.sin_addr),
REQ_DATASIZE);
::PostMessage(m_hWnd,WM_MSG_STATUS, 1, (LPARAM) AllocBuffer(str)); // Ping multiple times
for (nLoop = 0; nLoop < nRetries; nLoop++)
{
// Send ICMP echo request
TRACE("ping %s \n",pstrHost);
SendEchoRequest(rawSocket, &saDest); nRet = WaitForEchoReply(rawSocket);
if (nRet == SOCKET_ERROR)
{
WSAError("select()");
break;
}
if (!nRet)
{
str.Format("Request Timed Out");
::PostMessage(m_hWnd,WM_MSG_STATUS, 3, (LPARAM) AllocBuffer(str));
}
else { // Receive reply
dwTimeSent = RecvEchoReply(rawSocket, &saSrc, &cTTL); // Calculate elapsed time
dwElapsed = GetTickCount() - dwTimeSent;
str.Format("Reply[%d] from: %s: bytes=%d time=%ldms TTL=%d",
nLoop+1,
inet_ntoa(saSrc.sin_addr),
REQ_DATASIZE,
dwElapsed,
cTTL); ::PostMessage(m_hWnd,WM_MSG_STATUS, 2, (LPARAM) AllocBuffer(str)); Sleep(1);
}
}
::PostMessage(m_hWnd,WM_PING_END, 0, 1); nRet = closesocket(rawSocket);
if (nRet == SOCKET_ERROR)
WSAError("closesocket()");}
int CPing::SendEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr)
{
static ECHOREQUEST echoReq;
static nId = 1;
static nSeq = 1;
int nRet; // Fill in echo request
echoReq.icmpHdr.Type = ICMP_ECHOREQ;
echoReq.icmpHdr.Code = 0;
echoReq.icmpHdr.Checksum = 0;
echoReq.icmpHdr.ID = nId++;
echoReq.icmpHdr.Seq = nSeq++; // Fill in some data to send
for (nRet = 0; nRet < REQ_DATASIZE; nRet++)
echoReq.cData[nRet] = ' '+nRet; // Save tick count when sent
echoReq.dwTime = GetTickCount(); // Put data in packet and compute checksum
echoReq.icmpHdr.Checksum = in_cksum((u_short *)&echoReq, sizeof(ECHOREQUEST)); // Send the echo request
nRet = sendto(s, /* socket */
(LPSTR)&echoReq, /* buffer */
sizeof(ECHOREQUEST),
0, /* flags */
(LPSOCKADDR)lpstToAddr, /* destination */
sizeof(SOCKADDR_IN)); /* address length */ if (nRet == SOCKET_ERROR)
WSAError("sendto()");
return (nRet);
}
DWORD CPing::RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL)
{
ECHOREPLY echoReply;
int nRet;
int nAddrLen = sizeof(struct sockaddr_in); // Receive the echo reply
nRet = recvfrom(s, // socket
(LPSTR)&echoReply, // buffer
sizeof(ECHOREPLY), // size of buffer
0, // flags
(LPSOCKADDR)lpsaFrom, // From address
&nAddrLen); // pointer to address len // Check return value
if (nRet == SOCKET_ERROR)
WSAError("recvfrom()"); // return time sent and IP TTL
*pTTL = echoReply.ipHdr.TTL; return(echoReply.echoRequest.dwTime);
}
int CPing::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));
}void CPing::WSAError(LPCSTR lpMsg)
{
CString strMsg;
strMsg.Format("%s - WSAError: %ld",lpMsg,WSAGetLastError());
::PostMessage(m_hWnd,WM_MSG_STATUS, 0, (LPARAM) AllocBuffer(strMsg));
}u_short CPing::in_cksum(u_short *addr, int len)
{
register int nleft = len;
register u_short *w = addr;
register u_short answer;
register int sum = 0; /*
* Our algorithm is simple, using a 32 bit accumulator (sum),
* we add sequential 16 bit words to it, and at the end, fold
* back all the carry bits from the top 16 bits into the lower
* 16 bits.
*/
while( nleft > 1 ) {
sum += *w++;
nleft -= 2;
} /* mop up an odd byte, if necessary */
if( nleft == 1 ) {
u_short u = 0; *(u_char *)(&u) = *(u_char *)w ;
sum += u;
} /*
* add back carry outs from top 16 bits to low 16 bits
*/
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return (answer);
}这个例子是从网站上下的,自己建立了一个CWinThread的线程。
里面包括CPing的对象。
现在有个问题,void CPing::Ping(UINT nRetries,LPCSTR pstrHost,HWND hWnd)
函数里面多线程可能同时发包,比如20个ip地址,有的ip目前不同,
可能WaitForEchoReply收到回应时间比较长。
比如192.168.2.10和192.168.2.20,如果192.168.2.10不通,192.168.2.20通。
同时ping的时候,192.168.2.10的线程可能会收到192.168.2.20返回的消息,认为是连接的。
如果判断返回消息的ip啊?程序改如何改啊。
弄了2天了,希望大家帮忙啊。
{
SOCKET rawSocket;
LPHOSTENT lpHost;
UINT nLoop;
int nRet;
struct sockaddr_in saDest;
struct sockaddr_in saSrc;
DWORD dwTimeSent;
DWORD dwElapsed;
u_char cTTL; m_hWnd = hWnd; CString str; ASSERT(IsWindow(hWnd));
// Create a Raw socket
rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (rawSocket == SOCKET_ERROR)
{
WSAError("socket()");
return;
}
// Lookup host
lpHost = gethostbyname(pstrHost);
if (lpHost == NULL)
{
str.Format("Host not found: %s", pstrHost);
::PostMessage(m_hWnd,WM_MSG_STATUS, 0, (LPARAM) AllocBuffer(str));
::PostMessage(m_hWnd,WM_PING_END, 0, 0);
return;
}
// Setup destination socket address
saDest.sin_addr.s_addr = *((u_long FAR *) (lpHost->h_addr));
saDest.sin_family = AF_INET;
saDest.sin_port = 0; // Tell the user what we're doing
str.Format("Pinging %s [%s] with %d bytes of data:",
pstrHost,
inet_ntoa(saDest.sin_addr),
REQ_DATASIZE);
::PostMessage(m_hWnd,WM_MSG_STATUS, 1, (LPARAM) AllocBuffer(str)); // Ping multiple times
for (nLoop = 0; nLoop < nRetries; nLoop++)
{
// Send ICMP echo request
TRACE("ping %s \n",pstrHost);
SendEchoRequest(rawSocket, &saDest); nRet = WaitForEchoReply(rawSocket);
if (nRet == SOCKET_ERROR)
{
WSAError("select()");
break;
}
if (!nRet)
{
str.Format("Request Timed Out");
::PostMessage(m_hWnd,WM_MSG_STATUS, 3, (LPARAM) AllocBuffer(str));
}
else { // Receive reply
dwTimeSent = RecvEchoReply(rawSocket, &saSrc, &cTTL); // Calculate elapsed time
dwElapsed = GetTickCount() - dwTimeSent;
str.Format("Reply[%d] from: %s: bytes=%d time=%ldms TTL=%d",
nLoop+1,
inet_ntoa(saSrc.sin_addr),
REQ_DATASIZE,
dwElapsed,
cTTL); ::PostMessage(m_hWnd,WM_MSG_STATUS, 2, (LPARAM) AllocBuffer(str)); Sleep(1);
}
}
::PostMessage(m_hWnd,WM_PING_END, 0, 1); nRet = closesocket(rawSocket);
if (nRet == SOCKET_ERROR)
WSAError("closesocket()");}
int CPing::SendEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr)
{
static ECHOREQUEST echoReq;
static nId = 1;
static nSeq = 1;
int nRet; // Fill in echo request
echoReq.icmpHdr.Type = ICMP_ECHOREQ;
echoReq.icmpHdr.Code = 0;
echoReq.icmpHdr.Checksum = 0;
echoReq.icmpHdr.ID = nId++;
echoReq.icmpHdr.Seq = nSeq++; // Fill in some data to send
for (nRet = 0; nRet < REQ_DATASIZE; nRet++)
echoReq.cData[nRet] = ' '+nRet; // Save tick count when sent
echoReq.dwTime = GetTickCount(); // Put data in packet and compute checksum
echoReq.icmpHdr.Checksum = in_cksum((u_short *)&echoReq, sizeof(ECHOREQUEST)); // Send the echo request
nRet = sendto(s, /* socket */
(LPSTR)&echoReq, /* buffer */
sizeof(ECHOREQUEST),
0, /* flags */
(LPSOCKADDR)lpstToAddr, /* destination */
sizeof(SOCKADDR_IN)); /* address length */ if (nRet == SOCKET_ERROR)
WSAError("sendto()");
return (nRet);
}
DWORD CPing::RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL)
{
ECHOREPLY echoReply;
int nRet;
int nAddrLen = sizeof(struct sockaddr_in); // Receive the echo reply
nRet = recvfrom(s, // socket
(LPSTR)&echoReply, // buffer
sizeof(ECHOREPLY), // size of buffer
0, // flags
(LPSOCKADDR)lpsaFrom, // From address
&nAddrLen); // pointer to address len // Check return value
if (nRet == SOCKET_ERROR)
WSAError("recvfrom()"); // return time sent and IP TTL
*pTTL = echoReply.ipHdr.TTL; return(echoReply.echoRequest.dwTime);
}
int CPing::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));
}void CPing::WSAError(LPCSTR lpMsg)
{
CString strMsg;
strMsg.Format("%s - WSAError: %ld",lpMsg,WSAGetLastError());
::PostMessage(m_hWnd,WM_MSG_STATUS, 0, (LPARAM) AllocBuffer(strMsg));
}u_short CPing::in_cksum(u_short *addr, int len)
{
register int nleft = len;
register u_short *w = addr;
register u_short answer;
register int sum = 0; /*
* Our algorithm is simple, using a 32 bit accumulator (sum),
* we add sequential 16 bit words to it, and at the end, fold
* back all the carry bits from the top 16 bits into the lower
* 16 bits.
*/
while( nleft > 1 ) {
sum += *w++;
nleft -= 2;
} /* mop up an odd byte, if necessary */
if( nleft == 1 ) {
u_short u = 0; *(u_char *)(&u) = *(u_char *)w ;
sum += u;
} /*
* add back carry outs from top 16 bits to low 16 bits
*/
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return (answer);
}这个例子是从网站上下的,自己建立了一个CWinThread的线程。
里面包括CPing的对象。
现在有个问题,void CPing::Ping(UINT nRetries,LPCSTR pstrHost,HWND hWnd)
函数里面多线程可能同时发包,比如20个ip地址,有的ip目前不同,
可能WaitForEchoReply收到回应时间比较长。
比如192.168.2.10和192.168.2.20,如果192.168.2.10不通,192.168.2.20通。
同时ping的时候,192.168.2.10的线程可能会收到192.168.2.20返回的消息,认为是连接的。
如果判断返回消息的ip啊?程序改如何改啊。
弄了2天了,希望大家帮忙啊。
可是我做的效果是会受影响。
我感觉
int CPing::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));
}
函数是不是需要解析哪个ip返回的信息啊
我在线程里面创建一个CPing成员,
如果多个线程同时CPing,之间可能会接受到别的ip返回的信息,不知道这个如何改啊?
select的时候可以判断ip地址吗?
system("start ping -n1 192.168.0.1 >1.txt");
system("start ping -n1 192.168.0.2 >2.txt");
system("start ping -n1 192.168.0.3 >3.txt");
然后读1.txt,2.txt,3.txt的内容判断呢
SendEchoRequest(rawSocket, &saDest);nRet = WaitForEchoReply(rawSocket);
怎么感觉这个线程之中不匹配啊?
一般ping会设置超时,比如1S超时,那么100时间就是100 * 1
我再发一遍
比较着急用
system("start ping -n 1 192.168.0.2 >2.txt");
system("start ping -n 1 192.168.0.3 >3.txt");
//...
system("start ping -n 1 192.168.0.100 >100.txt");
Sleep(5000);
然后读1.txt,2.txt,3.txt,...,100.txt的内容判断因为ping的前面有start,所以不会等上一个ping结束才开始下一个ping,100个和1个费时应该差不多。
其实说白了就是采取多进程的方法代替楼主多线程的方法。参考《UNIX编程艺术》