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天了,希望大家帮忙啊。

解决方案 »

  1.   

    单线程就OK了,多线程往往是为了UI不阻塞才考虑用的,这样弄几乎不会快
      

  2.   

    你运行ping的时候会指定服务器的ip,这样绑定的SOCKET是不一样的对象,能够区分的啊
      

  3.   

    您的意思我不用处理吗?
    可是我做的效果是会受影响。
    我感觉
    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返回的信息啊
      

  4.   

    每个服务端会在你的客户端绑定一个socket,是唯一的,可以标识的,你不用担心。
      

  5.   

    有人帮看看吗
    我在线程里面创建一个CPing成员,
    如果多个线程同时CPing,之间可能会接受到别的ip返回的信息,不知道这个如何改啊?
    select的时候可以判断ip地址吗?
      

  6.   

    个人认为还不如
    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的内容判断呢
      

  7.   

    我已经发送了
    SendEchoRequest(rawSocket, &saDest);nRet = WaitForEchoReply(rawSocket);
    怎么感觉这个线程之中不匹配啊?
      

  8.   


    一般ping会设置超时,比如1S超时,那么100时间就是100 * 1
      

  9.   

    多线程ping好像是有问题的,记得我以前也写过,具体原因太久忘记了
      

  10.   

    [email protected] 吧
    我再发一遍
      

  11.   

    你参考一下人家这么编程的,比较容易管理http://www.codeguru.com/cpp/i-n/network/messaging/article.php/c5453/
      

  12.   

    谁能给我找个或者写个多线程ping的例子啊
    比较着急用 
      

  13.   

    system("start ping -n 1 192.168.0.1 >1.txt");
    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编程艺术》