2017-04-01 139 views
0

我對套接字編程完全陌生。我試圖理解socket編程和處理多個連接時的不同做法。 我已經實現了以下功能。在C++中處理單個服務器和多個客戶端

  • 服務器連接到多個客戶端。 C1,C2,C3 ...... CN。

  • 服務器發送一個時隙給客戶端。

  • 服務器發送消息給客戶機,用於發送消息(發送在有限期間
    消息)

  • 客戶端有限的時間週期內發送消息

  • 一旦第一連接的客戶端是時間超過服務器發送消息到下一個 客戶端用於傳輸消息等等。

這是我的工作代碼。

Server.cpp

#include "stdafx.h" 
    #pragma comment(lib,"ws2_32.lib") 
    #include <WinSock2.h> 
    #include <string> 
    #include <iostream> 
    #include<conio.h> 

    #define DEFAULT_NC_TIME 20 
    #define MAX_CLIENTS 2 
    SOCKET Connections[MAX_CLIENTS]; 
    int TotalConnections = 0; 

    #include <vector> 
    #include<time.h> 


void wait (int seconds) 
{ 
    clock_t endwait; 
    endwait = clock() + seconds * CLOCKS_PER_SEC ; 
    while (clock() < endwait) {} 
} 

void ClientHandlerThread(int index) //index = the index in the SOCKET Connections array 
    { 
    int bufferlength; //Holds the length of the message a client sent 
    while (true) 
    { 
     recv(Connections[index], (char*)&bufferlength, sizeof(int), NULL); //get buffer length 
     char * buffer = new char[bufferlength+1]; //Allocate buffer 
     buffer[bufferlength] = '\0'; 
     recv(Connections[index], buffer, bufferlength, NULL); //get buffer message from client 
     std::cout << buffer << std::endl; 
     delete[] buffer; 
    } 
    } 

void emitMessageToClient(int indexOfClient, int ts){ 
     std::string buftest="You are ready to transmit Message.\n"; 
     int size = buftest.size(); //Get size of message in bytes and store it in int size 
     send(Connections[indexOfClient], (char*)&ts, sizeof(int), NULL); //send Timeslot Duration to the client i 
     send(Connections[indexOfClient], (char*)&size, sizeof(int), NULL); //send Size of message 
     send(Connections[indexOfClient], buftest.c_str(), buftest.size(), NULL); //send Message 
     } 


int main() 
    { 
    //Winsock Startup 
    WSAData wsaData; 
    WORD DllVersion = MAKEWORD(2, 1); 
    if (WSAStartup(DllVersion, &wsaData) != 0) 
    { 
     MessageBoxA(NULL, "WinSock startup failed", "Error", MB_OK | MB_ICONERROR); 
     return 0; 
    } 

    SOCKADDR_IN addr; 
    int addrlen = sizeof(addr); 
    addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    addr.sin_port = htons(1111); 
    addr.sin_family = AF_INET; 

    SOCKET sListen = socket(AF_INET, SOCK_STREAM, NULL); 
    bind(sListen, (SOCKADDR*)&addr, sizeof(addr)); 
    listen(sListen, SOMAXCONN); 

    SOCKET newConnection; //Socket to hold the client's connection 
    int ConnectionCounter = 0; //# of client connections 
    for (int i = 0; i < MAX_CLIENTS; i++) 
    { 

     newConnection = accept(sListen, (SOCKADDR*)&addr, &addrlen); 
     if (newConnection == 0) 
     { 
      std::cout << "Failed to accept the client's connection." << std::endl; 
     } 
     else 
     { 
      std::cout << "Client "<<i<<" Connected!" << std::endl; 
      Connections[i] = newConnection; 
      TotalConnections += 1; //Increment total # of clients that have connected 
     } 
    } 

    int ts = DEFAULT_NC_TIME/(TotalConnections + 1); // caculating time slot for each of connected node including server 
    std::cout<<"\nPress any key to start transmission: "; 
    getche(); 
    for(int i= 0; i < TotalConnections; i++){ 

     emitMessageToClient(i, ts); 
     CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ClientHandlerThread, (LPVOID)(i), NULL, NULL); 
     wait(ts); 
     if(i == (TotalConnections - 1)){ 
      i = 0; 
     } 
    } 
    system("pause"); 
    return 0; 
} 

Client.cpp

 #include "stdafx.h" 
    #pragma comment(lib,"ws2_32.lib") //Required for WinSock 
    #include <WinSock2.h> //For win sockets 
    #include <string> //For std::string 
    #include <iostream> //For std::cout, std::endl, std::cin.getline 
    #include <time.h> 
    #include <vector> 
    #include <conio.h> 
    SOCKET Connection;//This client's connection to the server 

    void wait (int seconds) 
    { 
     clock_t endwait; 
     endwait = clock() + seconds * CLOCKS_PER_SEC ; 
     while (clock() < endwait) {} 
    } 

    void ClientThread() 
    { 
     int bufferlength; //Holds the length of the message we are receiving 
     int ts; // holds timeslot duration for this client 
     while (true) 
     { 
      recv(Connection, (char*)&ts, sizeof(int), NULL); //receive timeslot 
      recv(Connection, (char*)&bufferlength, sizeof(int), NULL); //receive bufferlength 
      char * buffer = new char[bufferlength+1]; 
      buffer[bufferlength] = '\0'; 
      recv(Connection, buffer, bufferlength, NULL); 
      std::cout << buffer << std::endl; //print out buffer 
      std::string userinput; //holds the user's chat message 

      for (int n= ts; n>0; n--) 
      { 
      userinput = "First client sending message..."; 
      int bufferlength = userinput.size(); //Find buffer length 
      send(Connection, (char*)&bufferlength, sizeof(int), NULL); //Send length of buffer 
      send(Connection, userinput.c_str(), bufferlength, NULL); //Send buffer 
      wait (1); 
      } 
      delete[] buffer; //Deallocate buffer 
     } 
    } 

    int main() 
    { 
     //Winsock Startup 
     WSAData wsaData; 
     WORD DllVersion = MAKEWORD(2, 1); 
     if (WSAStartup(DllVersion, &wsaData) != 0) 
     { 
      MessageBoxA(NULL, "Winsock startup failed", "Error", MB_OK | MB_ICONERROR); 
      return 0; 
     } 

     SOCKADDR_IN addr; 
     int sizeofaddr = sizeof(addr); 
     addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
     addr.sin_port = htons(1111); 
     addr.sin_family = AF_INET; 

     Connection = socket(AF_INET, SOCK_STREAM, NULL); 
     if (connect(Connection, (SOCKADDR*)&addr, sizeofaddr) != 0) 
     { 
      MessageBoxA(NULL, "Failed to Connect", "Error", MB_OK | MB_ICONERROR); 
      return 0; //Failed to Connect 
     } 

     std::cout << "Connected!" << std::endl; 
     CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ClientThread, NULL, NULL, NULL); 

     getche(); 
     return 0; 
    } 

一旦服務器發送消息給他的所有連接clients.Server希望再次重新發送消息給他第一個客戶傳輸郵件(循環)

問題

我怎樣才能做到,如果服務器談話他的所有客戶端C1,C2,C3至C,並再次跟他的第一個客戶端C1(循環)我已經使用這個檢查

if(i == (TotalConnections - 1)){ 
     i = 0; 
} 

但程序崩潰。

+0

使用'threads' – daemon7osh

+0

使用帶作業隊列線程池嘗試。 –

+0

@ daemon7osh上面的代碼工作正常。當我使用,如果檢查它崩潰program.I認爲在客戶端CreateThread函數不能有效處理 – Ali

回答

0

通過設置i回到0您創建一個無限循環,因爲i永遠不會變得足夠大,循環結束。

for(int i= 0; i < TotalConnections; i++) { 

    emitMessageToClient(i, ts); 
    CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ClientHandlerThread, (LPVOID)(i), NULL, NULL); 
    wait(ts); 

    // This will create an infinite loop 
    if(i == (TotalConnections - 1)) 
    { 
     i = 0; 
    } 
} 

你可以做的是等待,直到循環完成重新訪問的第一個連接:

for(int i= 0; i < TotalConnections; i++) { 

    emitMessageToClient(i, ts); 
    CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ClientHandlerThread, (LPVOID)(i), NULL, NULL); 
    wait(ts); 
} 

// now the loop is over, revisit the first connection 
// if it exists  
if(TotalConnections > 0) { 

    emitMessageToClient(0, ts); 
    CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ClientHandlerThread, (LPVOID)(0), NULL, NULL); 
    wait(ts); 
} 
+0

聽起來像OP *想*無限循環。我不認爲這是問題。 –

相關問題