2013-01-18 50 views
1

即時通訊只是開始在c + +編碼,我想構建一個多線程服務器,但我有一些錯誤。首先,這裏是我得到的代碼:c + +多線程服務器與std ::線程鑄造變量

while(true){ 
     printf("waiting for a connection\n"); 
     csock = (int*)malloc(sizeof(int)); 

     if((*csock = accept(hsock, (sockaddr*)&sadr, &addr_size))!= -1) 
     { 
      printf("---------------------\nReceived connection from %s\n",inet_ntoa(sadr.sin_addr)); 
      //std::thread th(&Network::SocketHandler, NULL); 

      std::thread th(Network::SocketHandler, (void*)csock); 
      th.detach(); 
     } 
     else 
     { 
      fprintf(stderr, "Error accepting %d\n", errno); 
     } 
    } 

    } 


    void Network::SocketHandler(void* lp) 
    { 
     int *csock = (int*)lp; 

     char buffer[1024]; 
     int buffer_len = 1024; 
     int bytecount; 

     memset(buffer, 0, buffer_len); 
     if((bytecount = recv(*csock, buffer, buffer_len, 0))== -1){ 
      fprintf(stderr, "Error receiving data %d\n", errno); 

     } 
     printf("Received bytes %d\nReceived string \"%s\"\n", bytecount, buffer); 
     strcat(buffer, " SERVER ECHO"); 

     if((bytecount = send(*csock, buffer, strlen(buffer), 0))== -1){ 
      fprintf(stderr, "Error sending data %d\n", errno); 

     } 

     printf("Sent bytes %d\n", bytecount); 

    } 

我在這行編譯時得到一個錯誤:

std::thread th(Network::SocketHandler, (void*)csock); 

說: 的std ::螺紋::線程(_Callable & &,_args & & ...)[with _Callable = void(Network :: )(int); _args = {無效*}] 沒有已知的轉換用於從「參數1」到「空隙(網絡:: & &)(INT)」

如何解決這個問題?還是有更好的方式來創建一個多線程服務器的任何示例可能是其他職位?

+0

你可能會考慮看看Boost.Asio的C++網絡庫 –

回答

5

爲什麼你在傳遞一個void *而不是int *當明確你真正想要的是int *

只要改變函數簽名:

void Network::SocketHandler(int* csock) 

,並刪除在不調用的代碼的轉換:

std::thread th(Network::SocketHandler, csock); 

現在,你仍然會得到一個錯誤,這將是原因不同。 Network::SocketHandler是一個成員函數。它需要一個this指針。通常你會用類似object.SocketHandler(csock)objptr->SocketHandler(csock)的語法來調用這樣的函數。當你用::std::thread這樣稱呼時,你並沒有給它一個被調用的對象。它沒有this指針。

你應該做的是再次改變函數簽名:

static void Network::SocketHandler(int* csock) 

,然後你的代碼會工作得很好。它看起來不像該函數使用任何成員變量,所以它不需要指針this

在另一個筆記上,它看起來像你正在嘗試改寫原來爲pthreads寫的東西。如果我正在爲C++ 11線程庫做這件事,我會以一種非常不同的方式來做到這一點。

我看不到你的整個程序,所以我沒有真正的重新設計它的奢侈。但是,從我所看到的,我會做這些調整:

while(true){ 
     printf("waiting for a connection\n"); 
     int csock = -1; 

     if((csock = accept(hsock, (sockaddr*)&sadr, &addr_size))!= -1) 
     { 
      printf("---------------------\nReceived connection from %s\n",inet_ntoa(sadr.sin_addr)); 
      //std::thread th(&Network::SocketHandler, NULL); 

      std::thread th(Network::SocketHandler, csock); 
      th.detach(); 
     } 
     else 
     { 
      fprintf(stderr, "Error accepting %d\n", errno); 
     } 
    } 

    } 


    void Network::SocketHandler(int csock) 
    { 
     char buffer[1024]; 
     int buffer_len = 1024; 
     int bytecount; 

     memset(buffer, 0, buffer_len); 
     if((bytecount = recv(csock, buffer, buffer_len, 0))== -1){ 
      fprintf(stderr, "Error receiving data %d\n", errno); 

     } 
     printf("Received bytes %d\nReceived string \"%s\"\n", bytecount, buffer); 
     strcat(buffer, " SERVER ECHO"); 

     if((bytecount = send(csock, buffer, strlen(buffer), 0))== -1){ 
      fprintf(stderr, "Error sending data %d\n", errno); 

     } 

     printf("Sent bytes %d\n", bytecount); 

    } 

的變化是相當微妙的。 C++ 11線程庫允許您調用函數並提供它們的所有參數,並以線程安全的方式處理它。無需再通過void *,也不需要使用mallocnew爲這些參數創建存儲空間,只需將線程需要的參數直接傳遞給線程構造函數即可。

您的程序實際上存在內存泄漏。它永遠不會回收空間malloc s爲csock指向。如果它運行了很長時間,它將最終耗盡內存,因爲所有這些文件句柄的空間都不會被回收。

您的程序也可能有文件句柄泄漏。您看不到close插座Network::SocketHandler。但由於我對整個項目沒有看到,所以我無法確定。

+0

根據你的意見,哪種方式更好?這是最初爲pthreads寫的,但有些人告訴我,c + + 11線程更好。 – mjcs

+2

@ user1971401:稍後我會爲你寫點東西。這其實並沒有那麼大的改變。順便說一句,他們是對的,C++ 11線程更適合各種原因使用。 – Omnifarious

+1

@ user1971401:在那裏,我儘可能地改變了你的程序,我可以提供關於它的知識並解釋我的推理。 – Omnifarious