首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

eMule 源碼深度分析 (一):監聽 Socket 與客戶端連入處理

     編輯:關於C++

CListenSocket 職責

監聽本地埠,接受客戶端連入,維護連入 Socket 佇列。

關鍵函式解析

StartListening()

bool CListenSocket::StartListening() {
    bListening = true;
    // SO_REUSEADDR 可解決快速重啟 LowID 問題,但若埠被別程序佔用會導致雙程式監聽同埠
    if (!Create(thePrefs.GetPort(), SOCK_STREAM, FD_ACCEPT, thePrefs.GetBindAddrA(), FALSE))
        return false;
    if (!Listen()) return false;
    m_port = thePrefs.GetPort();
    return true;
}

ReStartListening()

非實際關閉/開啟埠,僅切換 bListening 標誌。當連線數過多暫停 (StopListening),連線數下降時呼叫此函式恢復接受。

OnAccept() 核心邏輯

void CListenSocket::OnAccept(int nErrorCode) {
    if (nErrorCode) return;
    m_nPendingConnections++;
    if (TooManySockets(true) && !theApp.serverconnect->IsConnecting()) {
        StopListening(); return;
    }
    if (!bListening) ReStartListening();

    while (m_nPendingConnections > 0) {
        m_nPendingConnections--;
        CClientReqSocket* newclient;
        SOCKADDR_IN SockAddr; int iSockAddrLen = sizeof(SockAddr);

        // 條件式接受 (WSAAccept + 回呼過濾)
        if (thePrefs.GetConditionalTCPAccept() && !thePrefs.GetProxySettings().UseProxy) {
            SOCKET sNew = WSAAccept(m_SocketData.hSocket, (SOCKADDR*)&SockAddr, &iSockAddrLen, AcceptConnectionCond, 0);
            // 錯誤處理:WSAEWOULDBLOCK 重設計數器;其他錯誤累計超過 10 次重建 Socket
            newclient = new CClientReqSocket;
            newclient->InitAsyncSocketExInstance();
            newclient->m_SocketData.hSocket = sNew;
            newclient->AttachHandle(sNew);
        } else {
            // 一般 Accept
            newclient = new CClientReqSocket;
            if (!Accept(*newclient, (SOCKADDR*)&SockAddr, &iSockAddrLen)) { /* 錯誤處理同上 */ }
        }

        AddConnection(); // 計數器+1

        // 安全性檢查
        if (SockAddr.sin_addr.S_un.S_addr == 0) 
            newclient->GetPeerName((SOCKADDR*)&SockAddr, &iSockAddrLen);
        if (theApp.ipfilter->IsFiltered(SockAddr.sin_addr.S_un.S_addr)) {
            newclient->Safe_Delete(); theStats.filteredclients++; continue;
        }
        if (theApp.clientlist->IsBannedClient(SockAddr.sin_addr.S_un.S_addr)) {
            newclient->Safe_Delete(); continue;
        }

        newclient->AsyncSelect(FD_WRITE | FD_READ | FD_CLOSE);
    }
}

關鍵機制

  • 條件式接受:WSAAccept 搭配回呼 AcceptConnectionCond 可在核心層過濾連線。
  • 錯誤恢復:WSAEWOULDBLOCK 重設待處理計數;連續錯誤 >10 次重建監聽 Socket。
  • IP 過濾與封禁:整合 ipfilter 與 clientlist 封禁清單。
  • 非同步事件:AsyncSelect 註冊讀/寫/關閉通知。

基於 eMule 0.47 版本分析。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved