程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 深入分析驢子系列(1)

深入分析驢子系列(1)

編輯:關於C++

一直在看驢子的代碼,網上進行深入分析的文章不多,也許 這和驢子的代碼量太大, 代碼質量不高也許有關系。但更多的也許是不想分享,捨不得分享。其實,它本身就是開 源的 不分享人家慢慢看也能看懂 。由於時間關系 我會陸續把分析的文章帖上來,與各 位網友分享,也希望大家拍磚 進行討論 也把你的心得分享出來。。系列分析文章如果沒 有特別注明 以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 );
  }
}

以上就是這個類 的 主要函數 剩下的都比較簡單,就不再。。。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved