深入分析驴子系列(1)

      一直在看驴子的代码,网上进行深入分析的文章不多,也许 这和驴子的代码量太大,代码质量不高也许有关系。但更多的也许是不想分享,舍不得分享。其实,它本身就是开源的  不分享人家慢慢看也能看懂 。由于时间关系 我会陆续把分析的文章帖上来,与各位网友分享,也希望大家拍砖 进行讨论 也把你的心得分享出来。。系列分析文章如果没有特别注明 以easy mule 0.47为准

CListenSocket  类 的作用就是 监听 等待客户端的socket 到来 并维护到来的套接字 把accept进来的套接字 加入到list 中

 

// 该函数的作用是创建本地的listensocket, 是否Accept 连接是由winsock消息驱动

bool CListenSocket::StartListening()

{

     bListening = true;

     // Creating the socket with SO_REUSEADDR may solve LowID issues if emule was restarted

     // quickly or started after a crash, but(!) it will also create another problem. If the

     // socket is already used by some other application (e.g. a 2nd emule), we though bind

     // to that socket leading to the situation that 2 applications are listening at the same

     // port!

     if (!Create(thePrefs.GetPort(), SOCK_STREAM, FD_ACCEPT, thePrefs.GetBindAddrA(), FALSE/*bReuseAddr*/))

         return false;

     if (!Listen())  

         return false;

     m_port = thePrefs.GetPort();

     return true;

}

// 该函数改名为RestartAccept 更合适

// 它的本意是重新开始接受连接

// 为什么需要重新开始接受连接呢,原因是连接数过多情况下,

// 会暂时StopListeing (bListening 设置为false;) ,

// 连接数少的情况下会重新开始接受连接RestartListening;

// 应该注意的是:这个暂停和重新开始并不实际关闭/打开本地listen端口,只是设置一个bool标志

void CListenSocket::ReStartListening()

{

     bListening = true;

     ASSERT( m_nPendingConnections >= 0 );

     if (m_nPendingConnections > 0)

     {

         m_nPendingConnections--;

         OnAccept(0);

     }

}

连接到来

void CListenSocket::OnAccept(int nErrorCode)
{
    if (!nErrorCode)            //先判断是否有错误
    {
        m_nPendingConnections++;
        if (m_nPendingConnections < 1)
        {
            ASSERT(0);
            m_nPendingConnections = 1;
        }

        if (TooManySockets(true) && !theApp.serverconnect->IsConnecting())  //如果已经连接的套接字过多 或者 连接断开
        {                                                                    // 则停止监听返回            
            StopListening();
            return;
        }
        else if (!bListening)
            ReStartListening(); //If the client is still at maxconnections, this will allow it to go above it.. But if you don't, you will get a lowID on all servers.
    
        uint32 nFataErrors = 0;
        while (m_nPendingConnections > 0)
        {
            m_nPendingConnections--;

            CClientReqSocket* newclient;
            SOCKADDR_IN SockAddr = {0};
            int iSockAddrLen = sizeof SockAddr;
            if (thePrefs.GetConditionalTCPAccept() && !thePrefs.GetProxySettings().UseProxy)
            {
                _iAcceptConnectionCondRejected = 0;
                SOCKET sNew = WSAAccept(m_SocketData.hSocket, (SOCKADDR*)&SockAddr, &iSockAddrLen, AcceptConnectionCond, 0); // 这是调用API接受连接
                if (sNew == INVALID_SOCKET)
                {
                    DWORD nError = GetLastError();  // 根据返回的异常进行处理
                    if (nError == WSAEWOULDBLOCK)
                    {
                        DebugLogError(LOG_STATUSBAR, _T("%hs: Backlogcounter says %u connections waiting, Accept() says WSAEWOULDBLOCK - setting counter to zero!"), __FUNCTION__, m_nPendingConnections);
                        m_nPendingConnections = 0;
                        break;
                    }
                    else
                    {
                        if (nError != WSAECONNREFUSED || _iAcceptConnectionCondRejected == 0){
                            DebugLogError(LOG_STATUSBAR, _T("%hs: Backlogcounter says %u connections waiting, Accept() says %s - setting counter to zero!"), __FUNCTION__, m_nPendingConnections, GetErrorMessage(nError, 1));
                            nFataErrors++;
                        }
                        else if (_iAcceptConnectionCondRejected == 1)
                            theStats.filteredclients++;
                    }
                    if (nFataErrors > 10)
                    {
                        // the question is what todo on a error. We cant just ignore it because then the backlog will fill up
                        // and lock everything. We can also just endlos try to repeat it because this will lock up eMule
                        // this should basically never happen anyway
                        // however if we are in such a position, try to reinitalize the socket.
                        DebugLogError(LOG_STATUSBAR, _T("%hs: Accept() Error Loop, recreating socket"), __FUNCTION__);
                        Close();
                        StartListening();
                        m_nPendingConnections = 0;
                        break;
                    }
                    continue;
                }
                newclient = new CClientReqSocket;  // 一个新的套接字
                VERIFY( newclient->InitAsyncSocketExInstance() );
                newclient->m_SocketData.hSocket = sNew;
                newclient->AttachHandle(sNew);

                AddConnection();
            }
            else
            {
                newclient = new CClientReqSocket;
                if (!Accept(*newclient, (SOCKADDR*)&SockAddr, &iSockAddrLen))
                {
                    newclient->Safe_Delete();
                    DWORD nError = GetLastError();
                    if (nError == WSAEWOULDBLOCK)
                    {
                        DebugLogError(LOG_STATUSBAR, _T("%hs: Backlogcounter says %u connections waiting, Accept() says WSAEWOULDBLOCK - setting counter to zero!"), __FUNCTION__, m_nPendingConnections);
                        m_nPendingConnections = 0;
                        break;
                    }
                    else
                    {
                        DebugLogError(LOG_STATUSBAR, _T("%hs: Backlogcounter says %u connections waiting, Accept() says %s - setting counter to zero!"), __FUNCTION__, m_nPendingConnections, GetErrorMessage(nError, 1));
                        nFataErrors++;
                    }
                    if (nFataErrors > 10){
                        // the question is what todo on a error. We cant just ignore it because then the backlog will fill up
                        // and lock everything. We can also just endlos try to repeat it because this will lock up eMule
                        // this should basically never happen anyway
                        // however if we are in such a position, try to reinitalize the socket.
                        DebugLogError(LOG_STATUSBAR, _T("%hs: Accept() Error Loop, recreating socket"), __FUNCTION__);
                        Close();
                        StartListening();
                        m_nPendingConnections = 0;
                        break;
                    }
                    continue;
                }
        
                AddConnection();
    
                if (SockAddr.sin_addr.S_un.S_addr == 0) // for safety..
                {
                    iSockAddrLen = sizeof SockAddr;
                    newclient->GetPeerName((SOCKADDR*)&SockAddr, &iSockAddrLen);
                    DebugLogWarning(_T("SockAddr.sin_addr.S_un.S_addr == 0;  GetPeerName returned %s"), ipstr(SockAddr.sin_addr.S_un.S_addr));
                }
    
                ASSERT( SockAddr.sin_addr.S_un.S_addr != 0 && SockAddr.sin_addr.S_un.S_addr != INADDR_NONE );
    
                if (theApp.ipfilter->IsFiltered(SockAddr.sin_addr.S_un.S_addr))
                {
                    if (thePrefs.GetLogFilteredIPs())
                        AddDebugLogLine(false, _T("Rejecting connection attempt (IP=%s) - IP filter (%s)"), ipstr(SockAddr.sin_addr.S_un.S_addr), theApp.ipfilter->GetLastHit());
                    newclient->Safe_Delete();
                    theStats.filteredclients++;
                    continue;
                }
    
                if (theApp.clientlist->IsBannedClient(SockAddr.sin_addr.S_un.S_addr))
                {
                    if (thePrefs.GetLogBannedClients())
                    {
                        CUpDownClient* pClient = theApp.clientlist->FindClientByIP(SockAddr.sin_addr.S_un.S_addr);
                        AddDebugLogLine(false, _T("Rejecting connection attempt of banned client %s %s"), ipstr(SockAddr.sin_addr.S_un.S_addr), pClient->DbgGetClientInfo());
                    }
                    newclient->Safe_Delete();
                    continue;
                }
            }
            newclient->AsyncSelect(FD_WRITE | FD_READ | FD_CLOSE);
        }

        ASSERT( m_nPendingConnections >= 0 );
    }
}

 

以上就是这个类的 主要函数 剩下的都比较简单,就不再。。。

 

 

 

 

 

posted @ 2008-11-07 18:46  wangok  阅读(580)  评论(3)    收藏  举报