2017-03-08 60 views
0

在窗口的多個客戶端連接到單個服務器我已經寫了客戶端和服務器在C++,可以處理多個客戶端程序。現在的問題是:多線程在C++

我在服務器的main()函數中啓動了兩個線程,以便一個線程監聽(打開)與客戶端的連接,另一個線程接受連接並將數據發送到連接的客戶端。這兩個線程都定期運行(即連續)。

現在,當我連接的客戶機1向服務器的客戶端1接收的同時另一個客戶端2連接到然後客戶機1將進入等待狀態和客戶端2得到的數據的服務器的信息和時。現在,當我關閉客戶端2時,服務器顯示我兩個客戶端都斷開連接,但客戶端1正在運行,因爲它處於無限循環中,並且由於線程將定期運行,服務器將再次開始監聽並再次接受連接。這會與client1建立新的連接,並且客戶端1正在接收數據。

誰能幫我消除這種。我需要同時將數據發送到連接到服務器,當任何客戶端斷開,不應該影響其他客戶端的客戶端數量。一個可以處理多個客戶端的簡單服務器。

我的服務器程序:

#include <iostream> 
#include <winsock2.h> 
#include <Windows.h> 
#include <process.h> 
#include <thread> 
#pragma comment(lib,"ws2_32.lib") 


static int flag = 0; 
BOOL bOptVal = FALSE; 
WSADATA WsaDat; 
SOCKET Socket; 
std:: thread t1,t2,t3; 
void client_disconnected(SOCKET Socket); 
void startThreads(); 
void timer_start(std::function<void(void)> func, unsigned int interval); 
void accept_connection(); 
void send_message(); 

void start_server_listening() 
{ 

if(WSAStartup(MAKEWORD(2,2),&WsaDat)!=0) 
{ 
    std::cout<<"WSA Initialization failed!\r\n"; 
    WSACleanup(); 
    system("PAUSE"); 

} 

Socket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);  

if (setsockopt(Socket, SOL_SOCKET, SO_REUSEADDR, (char *) &bOptVal, sizeof(bOptVal)) < 0) { 
    perror("setsockopt(SO_REUSEADDR) failed"); 
    exit(EXIT_FAILURE); 
} 

if(Socket==INVALID_SOCKET) 
{ 
    std::cout<<"Socket creation failed.\r\n"; 
    WSACleanup(); 
    system("PAUSE"); 

} 

SOCKADDR_IN serverInf; 
serverInf.sin_family=AF_INET; 
serverInf.sin_addr.s_addr=INADDR_ANY; 
serverInf.sin_port=htons(8888); 

if(bind(Socket,(SOCKADDR*)(&serverInf),sizeof(serverInf))==SOCKET_ERROR) 
{ 
    std::cout<<"Unable to bind socket!\r\n"; 
    WSACleanup(); 
    //system("PAUSE"); 

} 
else{ 
listen(Socket,3); 


accept_connection(); 
    } 
} 

void accept_connection() 
{ 

    SOCKET TempSock=SOCKET_ERROR; 
    while(TempSock==SOCKET_ERROR) 
    { 
     std::cout<<"\nWaiting for incoming connections\n"; 
     Sleep(2000); 
     TempSock=accept(Socket,NULL,NULL); 
    } 

    // If iMode!=0, non-blocking mode is enabled. 
    u_long iMode=1; 
    ioctlsocket(Socket,FIONBIO,&iMode); 

    Socket=TempSock; 
    std::cout<<"Client connected!\r\n\r\n"; 
    send_message(); 
    if(flag==1){ 
     Sleep(1000); 
     //system("PAUSE"); 
    } 
} 
void send_message() 
{ 
    for(;;) 
    { 
     int nError=WSAGetLastError(); 
     if(nError!=WSAEWOULDBLOCK&&nError!=0) 
     { 
      flag=1; 
      client_disconnected(Socket); 
      break; 

     } 
     else { 
     char *szMessage="Welcome to the server!\r\n"; 
     send(Socket,szMessage,strlen(szMessage),0); 
     Sleep(2000);    
     } 
    } 

} 
void client_disconnected(SOCKET Socket) 
{ 
    std::cout<<"Client disconnected!\r\n"; 

      // Shutdown our socket 
      shutdown(Socket,SD_SEND); 

      // Close our socket entirely 
      closesocket(Socket); 

      WSACleanup(); 

} 


int main() 
{ 
    // start a timer that executes threads periodically/continuously 
    timer_start(startThreads, 200); //calling timer function 
    while(true); 
    return 0; 

} 
void timer_start(std::function<void(void)> func, unsigned int interval) 
{ 
    std::thread([func, interval]() { // calling startThreads() function 
     while (true) 
     { 
      func(); 
      std::this_thread::sleep_for(std::chrono::milliseconds(interval)); 
     } 
    }).detach(); 
} 
void startThreads() 
{ 
     //starting two threads one starts listening and other accepts connections 
     t1 = std::thread(start_server_listening); 
     t2 = std:: thread(accept_connection); 
     t1.join(); 
     t2.join(); 

} 

我的客戶端程序:

#include <iostream> 
#include <winsock2.h> 
#include <Windows.h> 
#include <process.h> 
#include <thread> 
#pragma comment(lib,"ws2_32.lib") 

void startThreads(); 
void timer_start(std::function<void(void)> func, unsigned int interval); 
std:: thread t1; 

void receiveToClient() 
{ 
    WSADATA WsaDat; 
    if(WSAStartup(MAKEWORD(2,2),&WsaDat)!=0) 
    { 
     std::cout<<"Winsock error - Winsock initialization failed\r\n"; 
     WSACleanup(); 
     system("PAUSE"); 

    } 

    // Create our socket 

    SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 
    if(Socket==INVALID_SOCKET) 
    { 
     std::cout<<"Winsock error - Socket creation Failed!\r\n"; 
     WSACleanup(); 
     system("PAUSE"); 

    } 

    // Resolve IP address for hostname 
    struct hostent *host; 
    if((host=gethostbyname("localhost"))==NULL) 
    { 
     std::cout<<"Failed to resolve hostname.\r\n"; 
     WSACleanup(); 
     system("PAUSE"); 

    } 

    // Setup our socket address structure 
    SOCKADDR_IN SockAddr; 
    SockAddr.sin_port=htons(8888); 
    SockAddr.sin_family=AF_INET; 
    SockAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 

    // Attempt to connect to server 
    if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr))!=0) 
    { 
     std::cout<<"Failed to establish connection with server\r\n"; 
     WSACleanup(); 
     system("PAUSE"); 

    } 

    // If iMode!=0, non-blocking mode is enabled. 
    u_long iMode=1; 
    ioctlsocket(Socket,FIONBIO,&iMode); 

    // Main loop 
    for(;;) 
    { 
     int nError=WSAGetLastError(); 
     if(nError!=WSAEWOULDBLOCK&&nError!=0) 
       break; 
     // Display message from server 
     char buffer[1000]; 
     memset(buffer,0,999); 
     int inDataLength=recv(Socket,buffer,1000,0); 
     std::cout<<buffer; 

     //end client when server is disconnected 

     Sleep(2000); 
    } 

    WSACleanup(); 


} 

int main() 
{ 
    timer_start(startThreads, 200); 
    while(true); 
    return 0; 

} 
void timer_start(std::function<void(void)> func, unsigned int interval) 
{ 
    std::thread([func, interval]() { 
     while (true) 
     { 
      func(); 
      std::this_thread::sleep_for(std::chrono::milliseconds(interval)); 
     } 
    }).detach(); 
} 
void startThreads() 
{ 

    t1 = std::thread(receiveToClient); 
    t1.join(); 
} 
+0

The while(true);在主循環只保證你的程序將**從不**退出。對於連接處理,我將使用一個受互斥鎖保護的向量來存儲每個連接,並編寫一個函數,檢查連接是否打開,如果沒有連接,請將其刪除。 – JeremiahB

回答

0

我看你的代碼運行很多線程。他們中的大多數人只是等待,永遠不會完成。此外,你的Socket對象被放置在全局空間中。但對於每個使用它的線程,它都應該是本地的。例如,您可以在全局空間中放置一個連接列表。該列表必須從臨界區內的線程訪問。