当前位置:编程学习 > C#/ASP.NET >>

多线程使用不同原始socket发送ICMP的问题,求教高手!

写了一个代码,下面简单举例:
每个线程都有自己创建的原始socket:
    m_Socket = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,
        WSA_FLAG_OVERLAPPED);

然后每个线程都有不同的目的IP;
各自线程向目的IP发送ICMP检测报文(也就是ping包),每个线程发送后即刻调用recvfrom进行报文接收,如下:
        ulByteRcvCnt = recvfrom(m_Socket, m_pRcvData, MAX_DATASIZE, 0,
            (struct sockaddr*)&stIPSrc, &lSrcLen);
        if(SOCKET_ERROR == ulByteRcvCnt)
        {
            ulLastError = WSAGetLastError();
            if(WSAETIMEDOUT == ulLastError)
            {
                Lock();
                m_TimeOutArray.Add(tNow);
                UnLock();
            }
        }
        else
        {
            pstIcmpHdr = (struct icmp *)(m_pRcvData + sizeof(IpHeader));
            if((ICMP_ECHOREPLY == pstIcmpHdr->i_code)
                &&(pstIcmpHdr->i_id == (USHORT)m_ulThreadId))
            {
                DelayMsInfo* pDelay = (DelayMsInfo*)malloc(sizeof(DelayMsInfo));
                
                pDelay->tTime = tNow;
                pDelay->ulDelay = (GetTickCount() - ulMsStart)+1;
                Lock();
                m_DelayMsArray.Add(pDelay);
                UnLock();
            }
            else
            {
                assert(0);
            }
        }

但是最后出现了下面的问题:
线程A的socket_a向目的IP_A发出报文后,接收到的ICMP回复报文会被线程B的socket_b接收到,导致错误。见上面断言处:assert(0);

这里有几个疑惑:
1)难道原始socket在一个进程里面不能使用多个吗?若是一个进程里面使用多个,socket是如何区分的?(因为原始套接字不能像TCP/UDP那样绑定端口,是在不知道如何进行区分)
2) 原始套接字是否与进程号绑定了,也就是说原始socket只能在一个进程里有一个,多了就会乱?

请高手解答! --------------------编程问答-------------------- 下面发出自己的程序,麻烦高手看看,问题如何解决?
自己写的CIcmpsocket类简介:
1)通过构造函数得到目的IP,和接收icmp的超时时间,和持续发送的时长;
2)通过调用成员函数start来开始发包icmp探测的线程,也就是说一个类有自己的一个线程;
3)创建3个CIcmpsocket类的对象,赋予不同的目的IP,然后调用它们的start函数,使其开始进行各自的icmp探测;
结果出现3个线程互相收到不是自己的icmp回复报文。
麻烦高手解答

ULONG WINAPI IcmpSocketThreadProc(LPVOID lpParameter)
{
    CIcmpSocket *pThread;
    pThread = (CIcmpSocket *)lpParameter;
    pThread->Execute();
    
    ExitThread(0);
    return 1;
}
CIcmpSocket::CIcmpSocket(DWORD ulDstIP, DWORD ulDataSize, DWORD ulRcvTimeO, DWORD ulTestTime)
{
    m_Socket = INVALID_SOCKET;
    int iTimeout = 2000;/*2S超时*/
    DWORD ulLoop = 0;
    struct sockaddr stAddr = {0};
    
    m_ThreadHandle = NULL;
    m_tTestTime = ulTestTime;
    m_ulTimeOut = ulRcvTimeO;
    m_ulThreadId = 0;

    InitializeCriticalSection(&m_Section);

    memset(&m_IPHdr, 0, sizeof(IpHeader));
    memset(&m_IcmpHeader, 0, sizeof(IcmpHeader));
    memset(&m_Dest, 0, sizeof(m_Dest));

    if(INADDR_NONE == ulDstIP)
    {
        assert(0);
    }
    
    m_Dest.sin_family = AF_INET;
    m_Dest.sin_addr.S_un.S_addr = ulDstIP;
 

    m_ulDatasize = ulDataSize;

    m_ulDatasize += sizeof(IcmpHeader);
    m_pSndData = (char*)malloc(m_ulDatasize);
    if(NULL == m_pSndData)
    {
        assert(0);
    }

    m_pRcvData = (char*)malloc(MAX_DATASIZE);
    if(NULL == m_pRcvData)
    {
        assert(0);
    }
    //fill_icmp_data(m_pSndData, m_ulDatasize);
    m_bTerminate = false;
}

CIcmpSocket::~CIcmpSocket()
{
    if(m_Socket != INVALID_SOCKET)
    {
        closesocket(m_Socket);
        m_Socket = INVALID_SOCKET;
    }

    Lock();
    DWORD ulDelayCnt = m_DelayMsArray.GetSize();
    DelayMsInfo* pstDelay = NULL;
    
    for(DWORD ulLoop = 0; ulLoop < ulDelayCnt; ulLoop++)
    {
        pstDelay = (DelayMsInfo*)m_DelayMsArray[ulLoop];
        if(NULL != pstDelay)
        {
            free((void*)pstDelay);
        }
    }
    m_DelayMsArray.RemoveAll();
    UnLock();

    if(m_pSndData)
    {
        free(m_pSndData);
    }

    if(m_pRcvData)
    {
        free(m_pRcvData);
    }
}

void CIcmpSocket::Execute()
{
    int iTimeout = 0;

    m_ulThreadId = GetCurrentThreadId();
    if(WSAStartup(MAKEWORD(2,2), &m_wsaData) != 0)
    {
        assert(0);
    }
    
    m_Socket = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,
        WSA_FLAG_OVERLAPPED);
    if(INVALID_SOCKET == m_Socket)
    {
        assert(0);
    }
    iTimeout = (int)m_ulTimeOut;
    if(SOCKET_ERROR == setsockopt(m_Socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&iTimeout, sizeof(iTimeout)))
    {
        assert(0);
    }
    iTimeout = 1000;
    if(SOCKET_ERROR == setsockopt(m_Socket, SOL_SOCKET, SO_SNDTIMEO, (char*)&iTimeout, sizeof(iTimeout)))
    {
        assert(0);
    }
    while(!m_bTerminate)
    {
        Run();

        Sleep(10);
    }
    ExitThread(0);
    return;
}

void CIcmpSocket::fill_icmp_data(char * icmp_data, int datasize)
{
    IcmpHeader *icmp_hdr = NULL;
    char *datapart = NULL;
    
    icmp_hdr = (IcmpHeader*)icmp_data;
    
    icmp_hdr->i_type = ICMP_ECHO; //类型为ICMP_ECHO
    icmp_hdr->i_code = 0;
    icmp_hdr->i_id = (USHORT)m_ulThreadId; //识别号为进程号 
    icmp_hdr->i_cksum = 0; //校验和初始化
    icmp_hdr->i_seq = 0; //序列号初始化
    datapart = icmp_data + sizeof(IcmpHeader); //数据端的地址为icmp报文地址加上ICMP的首部长度
    
    memset(datapart, 'A', datasize - sizeof(IcmpHeader)); //这里我填充的数据全部为"A",你可以填充任何代码和数据,实际上木马和控制端之间就是通过数据段传递数据的。
    
    return;
}

// CheckSum函数是标准的校验和函数
USHORT CIcmpSocket::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);    
}

void CIcmpSocket::Lock(void)
{
    EnterCriticalSection(&m_Section);
    return ;
}

void CIcmpSocket::UnLock(void)
{
    LeaveCriticalSection(&m_Section);
    return ;
}

void CIcmpSocket::Start()
{
    if(NULL == m_ThreadHandle)
    {
        m_ThreadHandle = CreateThread(NULL,1000000, IcmpSocketThreadProc,(LPVOID)this,0,NULL);
    }    
    
    return ;
}

void CIcmpSocket::Stop()
{
    m_bTerminate = false;
}

bool CIcmpSocket::Run() 
{
    time_t tStart = time(NULL);
    time_t tNow = tStart;
    unsigned short usSeq = 0;
    DWORD ulByteSndCnt = 0;
    DWORD ulByteRcvCnt = 0;
    struct sockaddr stIPSrc = {0};
    int lSrcLen = sizeof(stIPSrc);
    DWORD ulMsStart  = 0;
    DWORD ulLastError = 0;
    DWORD ulLoop = 0;

    while((tNow - tStart) <= m_tTestTime)
    {
        IcmpHeader* pstIcmpHdr = (IcmpHeader*)m_pSndData;

        if( (GetTickCount()-ulMsStart) <= 2000)
        {
            Sleep(10);
            continue;
        }
        fill_icmp_data(m_pSndData, m_ulDatasize);
        pstIcmpHdr->i_cksum = 0;
        pstIcmpHdr->timestamp = GetTickCount();
        pstIcmpHdr->i_seq = usSeq;
        pstIcmpHdr->i_cksum = CheckSum((unsigned short*)m_pSndData, m_ulDatasize);
        
        ulMsStart = GetTickCount();
        ulByteSndCnt = sendto(m_Socket, m_pSndData, m_ulDatasize, 0,
            (struct sockaddr*)&m_Dest, sizeof(struct sockaddr));
        if(SOCKET_ERROR == ulByteSndCnt)
        {
            ulLastError = WSAGetLastError();
            if(WSAETIMEDOUT == ulLastError)
            {
                Lock();
                m_TimeOutArray.Add(tNow);
                UnLock();
                continue;
            }
            return false;
        }
        if(ulByteSndCnt < m_ulDatasize)
        {
            continue;
        }
        
        memset((void*)m_pRcvData, 0, MAX_DATASIZE);
        
        ulByteRcvCnt = recvfrom(m_Socket, m_pRcvData, MAX_DATASIZE, 0,
            (struct sockaddr*)&stIPSrc, &lSrcLen);
        if(SOCKET_ERROR == ulByteRcvCnt)
        {
            ulLastError = WSAGetLastError();
            if(WSAETIMEDOUT == ulLastError)
            {
                Lock();
                m_TimeOutArray.Add(tNow);
                UnLock();
            }
        }
        else
        {
            pstIcmpHdr = (struct icmp *)(m_pRcvData + sizeof(IpHeader));
            if((ICMP_ECHOREPLY == pstIcmpHdr->i_code)
                &&(pstIcmpHdr->i_id == (USHORT)m_ulThreadId))
            {
                DelayMsInfo* pDelay = (DelayMsInfo*)malloc(sizeof(DelayMsInfo));
                
                pDelay->tTime = tNow;
                pDelay->ulDelay = (GetTickCount() - ulMsStart)+1;
                Lock();
                m_DelayMsArray.Add(pDelay);
                UnLock();
            }
            else
            {
                assert(0);
            }
        }
        usSeq++;
        tNow = time(NULL);
        Sleep(10);
    }

    return true;
}

bool CIcmpSocket::GetStatistic(CDWordArray& TimeOutArray, CPtrArray& DelayMsArray)
{
    DWORD ulDelayCnt = 0;
    DWORD ulTimeOutCnt = 0;
    DelayMsInfo* pstDelay = NULL;
    DWORD ulLoop = 0;

    Lock();
    ulDelayCnt = m_DelayMsArray.GetSize();
    ulTimeOutCnt = m_TimeOutArray.GetSize();
    for(ulLoop = 0; ulLoop < ulDelayCnt; ulLoop++)
    {
        pstDelay = (DelayMsInfo*)m_DelayMsArray[ulLoop];
        if(NULL != pstDelay)
        {
            DelayMsInfo* pRetDelay = (DelayMsInfo*)malloc(sizeof(DelayMsInfo));
            memcpy(pRetDelay, pstDelay, sizeof(DelayMsInfo));
            DelayMsArray.Add(pRetDelay);
        }
    }

    for(ulLoop = 0; ulLoop < ulTimeOutCnt; ulLoop++)
    {
        TimeOutArray.Add(m_TimeOutArray[ulLoop]);
    }
    UnLock();

    return true;
} --------------------编程问答-------------------- 自己顶一下
补充:.NET技术 ,  VC.NET
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,