2015-05-22 56 views
1

我試圖做一個壓力測試的情況下,攻擊者嘗試嘗試大量的TCP連接到我的C++遊戲服務器一次。(WINSOCK)C++遊戲服務器:TCPAccept一次TCP連接過多

我做了一個簡單的程序,通過TCP端口 連接1000次到我的遊戲服務器。這裏是我的服務器接受連接:

bool serverIsOn = true; 
double listen = tcplisten(12345, 30000, 1); 
setnagle(listen, true); 

... 

while(serverIsOn){ 
    double playerSocket = tcpaccept(listen, 1); 
    if(playerSocket > -1){ 
     cout << "Got a new connection, socket ID: " << playerSocket << endl; 

     std::string ip = tcpip(playerSocket); 
     if(ipIsBanned(ip)) 
      closesocket(playerSocket); 
    } 
} 

這裏有tcplisten和tcpaccept的定義:

double tcplisten(double port, double max, double mode) 
{ 
    CSocket* sock = new CSocket(); 
    if(sock->tcplisten((int)port, (int)max,(int)mode)) 
     return AddSocket(sock); 
    delete sock; 
    return -1; 
} 

double tcpaccept(double sockid, double mode) 
{ 
    CSocket*sock = (CSocket*)sockets.item((int)sockid); 
    if(sock == NULL)return -1; 
    CSocket*sock2 = sock->tcpaccept((int)mode); 
    if(sock2 != NULL)return AddSocket(sock2); 
    return -1; 
} 

問題:服務器停止接受連接我的測試程序結束後。例如,如果我之後連接了我的遊戲(它只請求一個連接,而不是我的測試攻擊程序請求1000個連接),則遊戲甚至無法連接。我也看不到通過我的服務器上的控制檯輸出的任何連接。最後一次連接來自攻擊程序。就好像它再也不能接受,而某些東西已經崩潰,但我無法弄清楚什麼,沒有例外或錯誤。

這對我的服務器來說是一個巨大的問題,因爲任何人都可以輕易地使服務器崩潰並強制它必須重新啓動才能再次接受新的連接。

我該怎麼做才能解決這個問題?我的意思是我甚至嘗試將最大連接數設置爲30,000,但這並不起作用。即使它確實有效,有人可能會嘗試連接超過30,000次,使其無用。

編輯:

更深入以上的tcplisten和tcpaccept函數的定義:

bool CSocket::tcplisten(int port, int max, int mode) 
{ 
    if((sockid = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) return false; 
    SOCKADDR_IN addr; 
    addr.sin_family = AF_INET; 
    addr.sin_addr.s_addr = INADDR_ANY; 
    addr.sin_port = htons(port); 
    if(mode)setsync(1); 
    if(bind(sockid, (LPSOCKADDR)&addr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR) 
    { 
     closesocket(sockid); 
     return false; 
    } 
    if(listen(sockid, max) == SOCKET_ERROR) 
    { 
     closesocket(sockid); 
     //TEMP ADD 
     sockid = INVALID_SOCKET; 
     return false; 
    } 
    return true; 
} 


CSocket* CSocket::tcpaccept(int mode) 
{ 
    //TEMP REMOVE: if(sockid<0)return NULL; 
    if(sockid == INVALID_SOCKET) return NULL; 
    SOCKET sock2; 
    if((sock2 = accept(sockid, (SOCKADDR *)&SenderAddr, &SenderAddrSize)) != INVALID_SOCKET) 
    { 
     CSocket*sockit = new CSocket(sock2); 
     if(mode >=1)sockit->setsync(1); 
     return sockit; 
    } 

    return NULL; 
} 

編輯2: 這裏是AddSocket的定義:

int AddSocket(CSocket*b) 
{ 
    for(int i = 0; i < sockets.count; i ++) 
    { 
     if(sockets[i] == NULL) 
     { 
      sockets.set(i, b); 
      return i; 
     } 
    } 
    sockets.Add(b); 
    return sockets.count-1; 
} 
+0

當你調用'closesocket(sockid)'時,確保事後也設置'sockid = INVALID_SOCKET'。 'sockid <0'應該是'sockid == INVALID_SOCKET'。你爲什麼使用'double'來表示套接字而不是使用'SOCKET'或者至少'int'? 'SOCKET'句柄不是浮點值。一個什麼'AddSocket()'實際返回?如果IP被禁止,您將該值直接傳遞給'closesocket()'。你爲什麼不清理你客戶端的'CSocket'對象? –

+1

您傳遞給listen()的'max'值不能控制一次可以連接多少個客戶端,它控制着有多少客戶端可以在套接字的待辦事項中掛起,等待accept()接受它們。您必須使用自己的邏輯來控制一次連接的最大客戶端數量。如果accept()返回一個被接受的客戶端,並且你超出了你的最大限制,那麼立即關閉這個套接字。或者使用'WSAAccept()'而不是'accept()',這樣你就可以使用一個回調函數,當達到最大限制時拒絕掛起的客戶端。 –

+0

你的情況聽起來像是你的'while(serverIsOn)'循環已經停止運行,或者'accept()'被阻塞,等待新的客戶端永遠不會到達。但是,當套接字函數失敗時,或者在循環結束後您沒有輸出。添加這些消息,然後看看會發生什麼。 –

回答

0

如果你在Linux上,你可以使用tcp_tw_reuse sysctl的。

+0

服務器使用winsock函數在Windows上運行。 –