2012-03-31 113 views
0

當我從我的flash/as3 telnet客戶端發送套接字數據時,我在下面的代碼中獲取BufferOverrun的位置時遇到了很多問題。我主要是想找到更多的內存泄漏等,除了這個問題之外,還有一種比手工調試更容易檢查緩衝區溢出/溢出的方法嗎?在Socket服務器中跟蹤BufferOverrun

/* 
     MTSocketServer 
     -------------- 
     The purpose of this application is to have a client application that can connect to this server. 
     This server should be able to parse messages from connected users and to send them to other users. 
    */ 

    // Headers and Namespace 
    #include "stdafx.h" 
    #include "MTSocketServer.h" 
    using namespace std; 

    // Constants 
    #define BUFFERSIZE 1000 
    #define PORT 20248 

    // Global Variables 
    SOCKET server; 
    struct Client_Data 
    { 
     SOCKET client_socket; 
     string user_id; 
    }; 
    list<Client_Data> clients; 

    // Method Prototypes 
    UINT Server_Thread(LPVOID pParams); 
    UINT Client_Thread(LPVOID pParams); 
    string Recv_String(SOCKET listener); 
    void Send_String(const char* message, SOCKET sender); 
    bool Identity_Exists(string id); 

    int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) 
    { 
     AfxBeginThread(Server_Thread, NULL); 
     while(_getch() != 27); 

     closesocket(server); 
     WSACleanup(); 

     return 0; 
    } 

    UINT Server_Thread(LPVOID pParams) 
    { 
     // Spawn Server Thread 
     cout << "Main thread spawned, press ESC at any time to exit.\r\n"; 
     WSADATA wsa_data; 
     SOCKADDR_IN server_location; 

     if (int wsa_return_val = WSAStartup(0x101, &wsa_data) != 0) 
     { 
      cout << "Incorrect version of 'Ws2_32.dll'.\r\n"; 
      cout << "Client thread de-initialized.\r\n"; 
      AfxEndThread(0, true); 
      return 1; 
     } 

     server_location.sin_family = AF_INET; 
     server_location.sin_addr.s_addr = INADDR_ANY; 
     server_location.sin_port = htons(20248); 

     server = socket(AF_INET, SOCK_STREAM, NULL); 
     if (server == INVALID_SOCKET) 
     { 
      cout << "Socket creation error.\r\n"; 
      cout << "Client thread de-initialized.\r\n"; 
      AfxEndThread(0, true); 
      return 1; 
     } 

     if (bind(server, (SOCKADDR*)&server_location, sizeof(server_location)) != 0) 
     { 
      cout << "Socket binding error.\r\n"; 
      cout << "Client thread de-initialized.\r\n"; 
      AfxEndThread(0, true); 
      return 1; 
     } 

     if (listen(server, 10) != 0) 
     { 
      cout << "Socket listening error.\r\n"; 
      cout << "Client thread de-initialized.\r\n"; 
      AfxEndThread(0, true); 
      return 1; 
     } 

     SOCKET client; 
     SOCKADDR_IN client_location; 
     int len_of_client = sizeof(client_location); 
     bool abort = false; 

     while(abort == false) 
     { 
      client = accept(server, (SOCKADDR*)&client_location, &len_of_client); 

      // Spawn Client Thread 
      cout << "Connection from " << inet_ntoa(client_location.sin_addr) << ". Client thread spawned.\r\n"; 
      AfxBeginThread(Client_Thread, (LPVOID)client); 
     } 

     // De-Initialize Server Thread 
     cout << "Server thread de-initialized.\r\n"; 
     AfxEndThread(0, true); 
     return 0; 
    } 

    UINT Client_Thread(LPVOID pParams) 
    { 
     SOCKET client = (SOCKET)pParams; 
     string client_id = ""; 

     // Check if a client with the same ID is on already 
     send(client, "ID_ME", 6, 0); 
     client_id = Recv_String(client); 

     if (Identity_Exists(client_id)) 
     { 
      Send_String("That ID is already taken. Please try another.", client); 
     } else 
     { 
      cout << "Created ID " << client_id << " successfully\r\n"; 

      Send_String("Type 'send' to send a message, 'quit' to exit.", client); 

      Client_Data this_client; 
      this_client.user_id = client_id; 
      this_client.client_socket = client; 

      clients.push_back(this_client); 

      bool is_con = true; 
      while(is_con) 
      { 
       string response = Recv_String(client); 
       if (response == "send") 
       { 
        Send_String("What username to send to?", client); 
        string to_id = Recv_String(client); 

        if (Identity_Exists(to_id)) 
        { 
         Send_String("Type your message below: ", client); 
         string temp = Recv_String(client) + "\n\0"; 
         const char* message = temp.c_str(); 

         for (list<Client_Data>::iterator iterator = clients.begin(), end = clients.end(); iterator != end; ++iterator) 
         { 
          if (to_id == iterator->user_id) 
          { 
           SOCKET temp = iterator->client_socket; 
           cout << temp; 
           Send_String(message, temp); 
          } 
         } 
        } else 
        { 
         Send_String("Invalid username specified", client); 
        } 
       } 
       else if (response == "quit") 
       { 
        Send_String("Quit Command Issued", client); 
        break; 
       } 
       else 
       { 
        Send_String("Invalid Command Issued", client); 
       } 
      } 
     } 

     // De-Initialize Client Thread 
     closesocket(client); 
     cout << "Client thread de-initialized.\r\n"; 
     AfxEndThread(0, true); 
     return 0; 
    } 

    // Function to parse full string values since they are often recieved one at a time 
    string Recv_String(SOCKET listener) 
    { 
     char buffer[BUFFERSIZE]; 
     string temp; 
     int numofbytes = 0; 

     while (true) 
     { 
      int num = recv(listener, buffer, BUFFERSIZE, 0); 
      numofbytes++; 

      buffer[num] = '\0'; 
      if (buffer[num-1] == '\n') 
       break; 

      if(numofbytes >= BUFFERSIZE-1) 
       break; 

      temp += buffer; 
      strcpy(buffer, ""); 
     } 

     return temp; 
    } 

    void Send_String(const char* message, SOCKET sender) 
    { 
     char buffer[BUFFERSIZE]; 
     strcpy(buffer, message); 
     size_t size = strlen(message); 

     int sendtest = send(sender, buffer, size, 0); 
     strcpy(buffer, ""); 
    } 

    bool Identity_Exists(string id) 
    { 
     for (list<Client_Data>::iterator iterator = clients.begin(), end = clients.end(); iterator != end; ++iterator) 
     { 
      if (id == iterator->user_id) 
      { 
       return true; 
      } 
     } 

     return false; 
    } 

回答

0

buffer[num] = '\0';如果num恰好等於BUFFERSIZE寫入一個超出緩衝區。如果num恰好爲-1,它會在緩衝區下面寫入一個緩衝區,低於

if (buffer[num-1] == '\n')雖然不是一個緩衝區溢出,也是錯誤的。 \ n可以在緩衝區中的任何地方(從0到n-1)。

+0

啊,我一直在寫這個方法,因爲我一次只接收一個字節。你有一個好的方法來處理recv輸入到字符串的建議嗎? – winglerw28 2012-04-04 18:31:56

+0

個人而言,我會用C重寫它,因爲我沒有做C++。至少,我會添加一些緩衝區管理代碼,並刪除所有愚蠢的指示變量。 – wildplasser 2012-04-04 19:05:10