2016-08-13 177 views
0

我想通過這個服務器從客戶端A發送消息到客戶端B.我不知道我怎麼能得到這個?我能想到的一種方法是爲每個客戶端創建一個消息隊列,並在該消息隊列中添加消息,如果有人向該客戶端發送消息,並從該隊列發送給相應的客戶端?但我不確定我該如何執行此操作?誰能幫我這個 ?我可以通過服務器實現客戶端 - 客戶端通信嗎?

在任何時刻都可以有n個客戶。在這種情況下,向所有客戶廣播。

以下是我的服務器代碼。我已檢查用戶的用戶名和密碼。函數將負責發送消息給其他客戶端。

#include<stdio.h> 
#include <stdlib.h> 
#include<string.h> //strlen 
#include<sys/socket.h> 
#include<arpa/inet.h> //inet_addr 
#include<unistd.h> //write 

int main(int argc , char *argv[]) 
{ 
    int socket_desc , client_sock , c , read_size, pid; 
    struct sockaddr_in server , client; 
    char client_message[2000], message_sent[2000], message_recieve[2000]; 

    //Create socket 
    socket_desc = socket(AF_INET , SOCK_STREAM , 0); 
    if (socket_desc == -1) 
    { 
     printf("Could not create socket"); 
    } 
    puts("Socket created"); 

    //Prepare the sockaddr_in structure 
    server.sin_family = AF_INET; 
    server.sin_addr.s_addr = INADDR_ANY; 
    server.sin_port = htons(5550); 

    //Bind 
    if(bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0) 
    { 
     //print the error message 
     perror("bind failed. Error"); 
     return 1; 
    } 
    puts("bind done"); 

    //Listen 
    listen(socket_desc , 3); 

    while (1) { 
     //Accept and incoming connection 
     puts("Waiting for incoming connections..."); 
     c = sizeof(struct sockaddr_in); 

     // accept connection from an incoming client 
     client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c); 
     if (client_sock < 0) 
     { 
      perror("accept failed"); 
      return 1; 
     } 

     /* Create child process */ 
     pid = fork(); 
     if (pid == 0) { 
     /* This is the client process */ 
     close(socket_desc); 
     puts("Connection accepted"); 

     char username[50], password[50]; 

     memset(message_recieve, 0, sizeof message_recieve); 
     recv(client_sock , username , 2000 , 0); 
     printf("username of the user: %s", username); 

     memset(message_recieve, 0, sizeof message_recieve); 
     recv(client_sock , password , 2000 , 0); 
     printf("password of the user: %s", password); 

     FILE *f = fopen("registeredUsers.txt", "r"); 
     if (f == NULL) 
     { 
      printf("Error opening file!\n"); 
      exit(1); 
     } 

     char uname[50], pass[50]; 
     int login = 0; 
     while(fscanf(f, "%s %s\n", uname, pass) > 0) { 
      printf("Helllo %s %s", uname, pass); 
      if (strcmp(username, uname)==0 && strcmp(password, pass) == 0) { 
       login = 1; 
       break; 
      } 
     } 

     memset(message_sent, 0, sizeof message_sent); 
     if (login == 1) { 
      strcpy(message_sent,"\n Successfull Login\n"); 
      write(client_sock , message_sent , strlen(message_sent)); // Sends login status 
      insidePortal(client_sock, username); 
     } else { 
      strcpy(message_sent,"\nOops, wrong username or password. Please try again.\n"); 
      write(client_sock , message_sent , strlen(message_sent)); // Sends login status 
     } 




     fclose(f); 


     if(read_size == 0) 
     { 
      puts("Client disconnected"); 
      fflush(stdout); 
     } 
     else if(read_size == -1) 
     { 
     perror("recv failed"); 
     } 
     exit(0); 
    } else { 
     close(client_sock); 
    } 
    } 

    return 0; 
} 


void insidePortal(int client_sock, char username[50]) { 

} 
+0

分隔只有兩個連接的客戶端是很容易的,因爲那麼服務器基本上只是充當代理:服務器從客戶端A接收的所有內容只是發送到客戶端B,反之亦然。通過直接的「發送」呼叫將每個「recv」連接起來。在一個過程中完成所有工作(請記住過程彼此獨立)。 –

+1

我要麼使用'select'來處理單個線程中的所有連接,要麼使用線程(使用'pthread'函數)。分叉將是我的最後選擇。 – user3386109

+0

如果你想發送消息給另一個客戶端(從服務器),那麼你至少需要一個連接...當你使用'fork'時,你應該有現有的連接,然後讓進程通信或至少建立一些分叉後連接到另一個(在你的情況下'insidePortal'應該使用現有的連接或建立一個)。在這種情況下,線程比叉子更合適。 –

回答

2

我有這個很長的代碼中,我在實現你類似的事情過去寫的,但它的CPP,如果你想太多,我會在這裏發佈,但基本上使用消息隊列或者多流程規劃似乎有點對我沒用,如果我是你,我會以下列方式將其編程

客戶端代碼 - >兩個線程 Server代碼 - >兩個線程

Client有兩個線程,和三種功能,Connect/Send/Receive

  • Connect - 這個函數處理到服務器的連接,無論您是使用TCP它所處理的聽,接受,或者如果你使用一些基於UDP由協議,它只是處理它 - 確保你有一些connectin
  • Send - 該函數一些數據發送到服務器
  • Receive這functino從服務器接收數據

Client的流動將是以下:

  1. Client連接到服務器上Main thread
  2. 連接到服務器Client之後創建Second thread
  3. Main thread - Client進入一些循環,它從用戶讀取的數據作爲輸入,然後調用Send功能,並將其發送到服務器
  4. Second thread - Client進入某個循環,調用Receive 從服務器接收數據並在接收到數據時打印它VED

,處理Client,現在大概Server

Server - 有三個功能,有一種全局數據結構,稱爲鏈接 - 這將通過它的所有線程共享目錄(鏈表明顯),WaitForConnectionReceiveSendToAll

  • WaitForConnection - 簡單地調用socket API對「接受」功能(如果你使用TCP),或者如果你使用的是其他由協議,這個功能菊st阻止它嘗試等待傳入連接,當某個連接到達時,此函數將連接註冊到名爲Connection-List的所有連接的全局鏈接列表中,並帶有適當的套接字和客戶端數據
  • SendToAll - 只需重複所有Connection-List併爲該列表中的每個連接,它發送一些數據通過
  • Receive只是收到一些數據,但設置一些超時首先,這是非常重要的,以便接收不會阻止太久!

Server,流量爲以下幾點:

  1. Main thread及牡丹Second thread
  2. Main thread進入一些循環,從而不斷地得到連接,並將它們添加到Connection-List
  3. 內調用WaitForConnectionSecond thread進入某個循環,該循環通過Connection-List進行迭代,對於Connection-List內的每個連接,接收在相應的插座被調用時,如果一些數據是接收,SendToAll調用與所接收的數據,如果超時,沒有任何反應,該循環繼續且之後執行下一個循環迭代
  4. SendToAll將內Connection-List

這是一些非常簡單的多客戶與廣播服務器架構的數據到所有客戶端應該是很容易實現!我希望這可以幫助你

我提前道歉,因爲這是我寫的前一陣子所以它有很多內它築巢的代碼,很多評論!

-------------------------客戶端代碼----------------

// Main.cpp 
#include <thread> 
#include <winsock2.h> 
#include <ws2tcpip.h> 
#include <iostream> 

#pragma comment (lib, "Ws2_32.lib") 

#define NAME_LENGTH 40 
#define DEFAULT_BUFLEN 512 
#define DEFAULT_PORT "8888" 

void Receive(SOCKET* pscktConnection); 
void Send(SOCKET* pscktConnection); 

void main() 
{ 
    // Variable definition 
    int  nResult; 
    int  nNameLength = 0; 
    char  pcNameBuffer[NAME_LENGTH]; 
    SOCKET sckConnection = NULL; 
    WSADATA wsaData; 
    addrinfo addrAddressFormat; 
    addrinfo* paddrServerAddress; 

    // Code section 

    // Initialize Winsock 
    nResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 

    // If winsock dll loading has failed 
    if (nResult != 0) 
    { 
     std::cout << "Failed loading winsock DLL" << std::endl; 
    } 
    // DLL loaded successfully 
    else 
    { 
     //Setup connection info 
      ZeroMemory(&addrAddressFormat, sizeof(addrAddressFormat)); 
      addrAddressFormat.ai_family = AF_INET; 
      addrAddressFormat.ai_socktype = SOCK_STREAM; 
      addrAddressFormat.ai_protocol = IPPROTO_TCP; 

     // Resolve the server address and port with the address setting into our final address 
     nResult = getaddrinfo("10.0.0.5", DEFAULT_PORT, &addrAddressFormat, &paddrServerAddress); 

     // Address resolving has failed 
     if (nResult != 0) 
     { 
      std::cout << "Some error has occured during connection establishment" << std::endl; 
     } 
     else 
     { 
      // Request user for his name 
      pcNameBuffer[0] = '\0'; 
      std::cout << "PLEASE ENTER YOUR NAME -> "; 
      std::cin.getline(pcNameBuffer, NAME_LENGTH); 
      std::cout << std::endl << std::endl ; 

      // Creating the socket 
      sckConnection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 

      // Connecting 
      nResult = connect(sckConnection, paddrServerAddress->ai_addr, (int)paddrServerAddress->ai_addrlen); 


      // Creating of the socket has failed 
      if (nResult == SOCKET_ERROR) 
      { 
       std::cout << "Creating of the socket has failed" << std::endl; 
      } 
      // Send server user's name 
      else 
      { 
       // Measure the name length 
       while (pcNameBuffer[nNameLength] != '\0') 
       { 
        ++nNameLength; 
       } 

       // If invalid name 
       if (nNameLength == 0) 
       { 
        pcNameBuffer[0] = 'G'; 
        pcNameBuffer[1] = 'U'; 
        pcNameBuffer[2] = 'E'; 
        pcNameBuffer[3] = 'S'; 
        pcNameBuffer[4] = 'T'; 
        pcNameBuffer[5] = '\0'; 

        nNameLength = 6; 
       } 

       nResult = send(sckConnection, pcNameBuffer, nNameLength + 1, 0); 

       // An error has occured while sending server the user's name 
       if (nResult <= 0) 
       { 
        std::cout << "Some error has occured" << std::endl;    
       } 
       // Good to go 
       else 
       { 
        std::thread Read(Receive, &sckConnection); 
        Send(&sckConnection); 
       } 
      } 
     } 
    } 

    // cleanup resources 
    WSACleanup(); 
} 

/* 
* [Description]: This method is used only to read messages from server and print them 
* [Paramaters]: 
* pscktServerSocket - The address of the our connection socket 
* [Return Value]: none 
*/ 
void Receive(SOCKET* pscktConnection) 
{ 
    // Variable definition 
    int nReceivedBytes; 
    int nBufferLen = DEFAULT_BUFLEN; 
    char pcBuffer[DEFAULT_BUFLEN]; 

    // Code section 

    // Keep this operation running constantly 
    while (true) 
    { 
     // Read from server -- NO TIME OUT NEEDED 
     nReceivedBytes = recv((*pscktConnection), pcBuffer, nBufferLen, 0); 

     // More than zero bytes received 
     if (nReceivedBytes > 0) 
     { 
      // Set a zero termination to simulate a string 
      pcBuffer[nReceivedBytes] = '\0';    
      std::cout << pcBuffer << std::endl;  
     } 
     // Server has closed the connection probably 
     else 
     { 
      // TODO - CLOSE CONNECTION   
     } 
    } 
} 


/* 
* [Description]: This method is used only to send messages to the server 
* [Paramaters]: 
* pscktServerSocket - The address of the our connection socket 
* [Return Value]: none 
*/ 
void Send(SOCKET* pscktConnection) 
{ 
    // Variable definition 
    int nSentBytes; 
    int nBufferLen = DEFAULT_BUFLEN; 
    char pcBuffer[DEFAULT_BUFLEN]; 

    // Code section 

    pcBuffer[0] = '\0'; 

    // Keep this operation running constantly 
    while (true) 
    { 
     int nSentBytes = 0; 

     // Read 
     std::cin.getline(pcBuffer, nBufferLen); 

     // Go through string untill backslash 0 
     while (pcBuffer[nSentBytes] != '\0') 
     { 
      // Increase the number of bytes we want to send 
      ++nSentBytes; 
     }  

     pcBuffer[nSentBytes] = '\0'; 

     nSentBytes = send((*pscktConnection), pcBuffer, nSentBytes, 0); 

     // An error has occured 
     if (nSentBytes == SOCKET_ERROR) 
     { 
      // TODO - HANDLE ERROR; 
     } 
    } 
} 

`

-------------------------服務器代碼----------- -----

// Source.cpp 
#include <thread> 
#include <winsock2.h> 
#include <ws2tcpip.h> 
#include <iostream> 
#include "Client.h" 
#include "Connections.h" 

#pragma comment (lib, "Ws2_32.lib") 

#define NAME_LENGTH 40 
#define DEFAULT_BUFLEN 512 
#define DEFAULT_PORT "8888" 
#define MAX_CONNECTIONS 5 


// Globals 
Connections* conAllConnections = Connections::getInstance(); 

bool LoadServerSocket(SOCKET* pscktServerSocket); 
void Dispatcher(SOCKET* pscktServerSocket); 
void SendAll(ClientNode* pclndSenderAddress, char* pcMessageBuffer, int nLength); 
void HandleConnections(); 

void main() 
{ 
    // Variable definition 
    int  nResult; 
    SOCKET sckServerSocket = NULL; 
    WSADATA wsaData; 

    // Code section 

    // Initialize Winsock 
    nResult = WSAStartup(MAKEWORD(2, 2), &wsaData); 

    // If winsock dll loading has failed 
    if (nResult != 0) 
    { 
     std::cout << "Failed loading winsock DLL" << std::endl; 
    } 
    // DLL loaded successfully 
    else 
    { 
     // If failed loading the server socket 
     if (!LoadServerSocket(&sckServerSocket)) 
     { 
      std::cout << "Failed loading the server socket!" << std::endl; 
     } 
     else 
     { 
      std::thread dispatch(Dispatcher,&sckServerSocket); 
      //dispatch.join(); 
      HandleConnections(); 
     } 
    } 

    // cleanup resources 
    WSACleanup(); 
} 

/* 
* [Description]: This method is used to load and bind server socket into some pointer. 
* [Paramaters]: 
* pscktServerSocket - a pointer variable that we would like to load our socket into the address this pointer 
* is pointing at 
* [Return Value]: A boolean indication of whether our socket was created successfully 
*/ 
bool LoadServerSocket(SOCKET* pscktServerSocket) 
{ 
    // Variable definition 
    int  nResult; 
    bool  bWasServerSocketCreated = false; 
    bool  bWasAddressResolved  = false; 
    addrinfo addrAddressFormat; 
    addrinfo* paddrFinalAddress  = NULL; 

    // Code section 

    // Fil addrAddressFormat with zeros, and set correct settings of our desired socket 
    ZeroMemory(&addrAddressFormat, sizeof(addrAddressFormat)); 
    addrAddressFormat.ai_family = AF_INET; 
    addrAddressFormat.ai_socktype = SOCK_STREAM; 
    addrAddressFormat.ai_protocol = IPPROTO_TCP; 
    //addrAddressFormat.ai_flags = AI_PASSIVE; 

    // Resolve the server address and port with the address setting into our final address 
    nResult = getaddrinfo("10.0.0.5", DEFAULT_PORT, &addrAddressFormat, &paddrFinalAddress); 

    // If resolving of the address was successful 
    if (nResult == 0) 
    { 
     // Set address resolving bool indication to true 
     bWasAddressResolved = true; 

     // Create server socket 
     (*pscktServerSocket) = socket(paddrFinalAddress->ai_family, 
             paddrFinalAddress->ai_socktype, 
             paddrFinalAddress->ai_protocol); 

     // Socket creating was successful 
     if ((*pscktServerSocket) != INVALID_SOCKET) 
     { 
      // Set socket creation indication to true 
      bWasServerSocketCreated = true; 

      // Bind our socket into our address 
      nResult = bind((*pscktServerSocket), 
          paddrFinalAddress->ai_addr, 
          (int)paddrFinalAddress->ai_addrlen); 

      // In case binding failed 
      if (nResult == SOCKET_ERROR) 
      { 
       closesocket((*pscktServerSocket)); 
       bWasServerSocketCreated = false; 
      } 
     } 
    } 

    // Freeing resources 
    if (bWasAddressResolved) 
    { 
     freeaddrinfo(paddrFinalAddress); 
    } 

    return (bWasServerSocketCreated); 
} 

/* 
* [Description]: This uses the loaded server socket and handles incoming requests for connections 
* [Paramaters]: 
* pscktServerSocket - a pointer to the loaded server socket 
* [Return Value]: none 
*/ 
void Dispatcher(SOCKET* pscktServerSocket) 
{ 
    // Variable definition 
    int  nResult; 
    char pcBuffer[NAME_LENGTH]; 
    DWORD timeout  = 1500; 
    SOCKET sckClientSocket; 
    Client clntNewClient; 

    // Code section 

    // Keep this running constantly 
    while (true) 
    { 
     // Keep this running as long as we have the sufficient amount of connections 
     while (conAllConnections->getNumOfConnections() < MAX_CONNECTIONS) 
     { 
      // Attempt listening on the server socket 
      nResult = listen((*pscktServerSocket), MAX_CONNECTIONS); 

      // Listening was a failure 
      if (nResult == SOCKET_ERROR) 
      { 
       std::cout << "Failed listening with the server socket" << std::endl; 
       // HANDLE ERROR - TODO 
      } 
      // Listening was successful 
      else 
      { 
       std::cout << "Listening...." << std::endl; 
       // Accept a client socket 
       sckClientSocket = accept((*pscktServerSocket), NULL, NULL); 

       // Accepting was a failure 
       if (sckClientSocket == INVALID_SOCKET) 
       { 
        std::cout << "Client accepting has failed" << std::endl; 
        // HANDLE ERROR - TODO 
       } 
       // Client was added successfully 
       else 
       { 

        setsockopt(sckClientSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)); 

        nResult = recv(sckClientSocket, pcBuffer, NAME_LENGTH, 0); 

        // If received a valid username 
        if (nResult > 0) 
        { 
         timeout = 1; 

         std::cout << "New Client -> " << pcBuffer << std::endl; 
         clntNewClient.setClientSocket(sckClientSocket); 
         clntNewClient.setIsAdmin(false); 
         clntNewClient.setClientName(pcBuffer); 

         setsockopt(clntNewClient.getClientSocket(), SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)); 

         conAllConnections->Add(clntNewClient); 

         // Receive until the peer shuts down the connection   
        } 
       } 
      } 
     } 
    } 
} 

/* 
* [Description]: This method forwards a message to all other clients but the client who sent it 
* [Paramaters]: 
* pclndSenderAddress - The address of the client node who sent the 
* pcMessageBuffer- a pointer to the message buffer 
* nLength - the length of the message 
* [Return Value]: none 
*/ 
void SendAll(ClientNode* pclndSenderAddress, char* pcMessageBuffer, int nLength) 
{ 
    // Variable definition 
    int   nError; 
    int   nResult; 
    Client  clntCurrentClient; 
    ClientNode* pclndCurrentNode; 
    ClientNode* pclndNextNode; 

    // Code section 

    // Set first node 
    pclndCurrentNode = conAllConnections->getFirst(); 

    // Go through all connections 
    while (pclndCurrentNode != NULL) 
    { 
     // Save the next node in this phase of the code in order to avoid corruption of memory 
     // in case node would be deleted from dynamic allocated memory and we wont be able to call the next val upon it 
     pclndNextNode = pclndCurrentNode->getNext(); 

     // Compare addresses, we do not want to forward the message to the sender 
     if (pclndCurrentNode != pclndSenderAddress) 
     { 

      clntCurrentClient = pclndCurrentNode->getClient(); 

      // Forward the message 
      nResult = send(clntCurrentClient.getClientSocket(), pcMessageBuffer, nLength, 0); 

      // An error has occured 
      if (nResult == SOCKET_ERROR) 
      { 
       nError = WSAGetLastError(); 

       // TODO -- handle later 
      } 
     } 

     // Forward current node 
     pclndCurrentNode = pclndNextNode; 
    } 
} 

/* 
* [Description]: This method handles and receives messages from our clients and forwards them 
* [Paramaters]: none 
* [Return Value]: none 
*/ 
void HandleConnections() 
{ 
    // Variable definition 
    int   nIndex; 
    int   nError; 
    int   nRecvLen; 
    int   nNameLen; 
    int   nRecvbuflen = DEFAULT_BUFLEN; 
    char  pcBuffer[DEFAULT_BUFLEN + NAME_LENGTH + 3]; 
    Client  clntCurrentClient; 
    ClientNode* pclndCurrentNode; 
    ClientNode* pclndNextNode; 

    // Code section 

    // Keep this going constantly 
    while (true) 
    { 
     pclndCurrentNode = conAllConnections->getFirst(); 

     // Go through all connections 
     while (pclndCurrentNode != NULL) 
     { 
      clntCurrentClient = pclndCurrentNode->getClient(); 

      // Save the next node in this phase of the code in order to avoid corruption of memory 
      // in case node would be deleted from dynamic allocated memory and we wont be able to call the next val upon it 
      pclndNextNode = pclndCurrentNode->getNext(); 

      // Attempt receiving data from client 
      nRecvLen = recv(clntCurrentClient.getClientSocket(), pcBuffer, nRecvbuflen, 0); 

      // An error has occured 
      if (nRecvLen <= 0) 
      { 
       nError = WSAGetLastError(); 

       // if not a timeout error 
       if (nError != 10060) 
       { 
        std::cout << "Client removed" << std::endl; 

        // Socket error, remove connection 
        conAllConnections->Remove(pclndCurrentNode); 
       } 
      } 
      // No error has occured 
      else 
      { 
       //// The purpose of this part of the code is only to place a [CLIENTNAME] 
       //// prefix within the begining of each message 
       ////--------------------------------//// 

       // Get client's name length 
       nNameLen = clntCurrentClient.getNameLength(); 

       nIndex = nRecvLen - 1; 
       // Copy the message some offset forward -- offset is (namn length + 4) 
       while (nIndex >= 0) 
       { 
        // Copy letter (namelen + 4) times forward 
        pcBuffer[nIndex + nNameLen + 4] = pcBuffer[nIndex]; 

        // Reduce nIndex 
        --nIndex; 
       } 

       pcBuffer[0] = '['; 

       nIndex = 0; 

       // Place clients name within message 
       while (nIndex < nNameLen) 
       { 
        // + 1 for offset 
        pcBuffer[nIndex + 1] = (clntCurrentClient.getClientName())[nIndex]; 

        // Increase nIndex 
        ++nIndex; 
       } 

       pcBuffer[nIndex + 1] = ']'; 
       pcBuffer[nIndex + 2] = ':'; 
       pcBuffer[nIndex + 3] = ' '; 

       ////--------------------------------//// 
       //// No longer adding a prefix code 

       SendAll(pclndCurrentNode, pcBuffer, nRecvLen + nNameLen + 4); 
      } 

      // Forward current node 
      pclndCurrentNode = pclndNextNode; 
     } 
    } 
} 
//////////////////////////////////////////////////// 
// Connections.h 
#ifndef CONNECTIONS_H 
#define CONNECTIONS_H 
#include "ClientNode.h" 


class Connections 
{ 
    private: 

     // Data members 
     static Connections* _Instance; 
     int   nNumOfConnections; 
     ClientNode* pclndFirst; 

     // Ctor 
     Connections(); 

    public: 

     // Methods 
     void  Add(Client clntNewClient); 
     void  Remove(ClientNode* pclndClientToRemove); 
     int   getNumOfConnections(); 
     ClientNode* getFirst(); 

     // Static methods 
     static Connections* getInstance(); 
}; 

#endif 
//////////////////////////////////////////////////// 
// Connections.cpp 
#include "Connections.h" 

// Set instance to null 
Connections* Connections::_Instance = NULL; 

/* ------- PRIVATE CTOR ------- 
* [Description]: This method is the constructor of the Connections 
* [Paramaters]: none 
* [Return Value]: none 
*/ 
Connections::Connections() 
{ 
    this->nNumOfConnections = 0; 
    this->pclndFirst = NULL; 
} 

/* 
* [Description]: This method returns the amount of connections currently within our linked list 
* [Paramaters]: none 
* [Return Value]: The amount of connections 
*/ 
int Connections::getNumOfConnections(){ 

    return (this->nNumOfConnections); 
} 

/* 
* [Description]: This method returns a pointer to the first client node within our connection list 
* [Paramaters]: none 
* [Return Value]: A pointer to the first client node 
*/ 
ClientNode* Connections::getFirst() 
{ 
    return (this->pclndFirst); 
} 

/* 
* [Description]: This method adds a new client to the linkedlist of clients 
* [Paramaters]: 
* clntNewClient - The new client struct 
* [Return Value]: none 
*/ 
void Connections::Add(Client clntNewClient) 
{ 
    // Create a new client node 
    ClientNode* pclndNewClientNode = new ClientNode; 

    // Set the client node's client 
    pclndNewClientNode->setClient(clntNewClient); 

    // Set the client node's next client pointer to point at the currenly first address 
    pclndNewClientNode->setNext(this->getFirst()); 

    // Set the first client pointer to point at the new client node's address (Push it within the linked list) 
    this->pclndFirst = pclndNewClientNode; 

    // Increase the number of connection 
    ++(this->nNumOfConnections); 
} 

/* 
* [Description]: This method removes a client from our linked list of connections 
* [Paramaters]: 
* pclndClientToRemove - The address of the client node we wish to remove 
* [Return Value]: none 
*/ 
void Connections::Remove(ClientNode* pclndClientToRemove){ 

    // Variable definition 
    int   nIndex; 
    ClientNode* pclndCurrentNode; 

    // Code section 

    pclndCurrentNode = this->getFirst(); 

    // Checking if we need to remove the first node 
    if (pclndCurrentNode == pclndClientToRemove) 
    { 
     // Jump over deleted node 
     this->pclndFirst = pclndClientToRemove->getNext(); 

     // Free memory 
     delete pclndClientToRemove; 

     // Decrease amount of connections 
     --(this->nNumOfConnections); 
    } 
    // We do not need to remove the first one 
    else 
    { 
     // Go through all ClientNodes addresses 
     for (nIndex = 0; nIndex < (this->nNumOfConnections - 1); ++nIndex) 
     { 
      // If the next node is the node we wish to delete 
      if (pclndCurrentNode->getNext() == pclndClientToRemove) 
      { 
       // Set the current node next node to be the next node of the node we wish to delete 
       pclndCurrentNode->setNext(pclndClientToRemove->getNext()); 

       // free dynamically allocated memory 
       delete pclndClientToRemove; 

       // break outside the loop 
       break; 

       // Decrease amount of connections 
       --(this->nNumOfConnections); 
      } 
      // Next node is not the node we whish to delete 
      else 
      { 
       // Move to the next node 
       pclndCurrentNode = pclndCurrentNode->getNext(); 
      } 
     } 
    } 
} 

/* 
* [Description]: This method returns the only instance of Connections (SINGLETON PATTERN) 
* [Paramaters]: none 
* [Return Value]: A pointer to the single instance of connection 
*/ 
Connections* Connections::getInstance(){ 

    // If instance was not instantiated yet 
    if (_Instance == NULL) 
    { 
     // Call CTOR 
     _Instance = new Connections(); 
    } 

    return (_Instance); 
} 
//////////////////////////////////////////////////// 
// ClientNode.h 
#ifndef CLIENTNODE_H 
#define CLIENTNODE_H 
#include "Client.h" 

class ClientNode 
{ 
    // Data members 
    Client clntClient; 
    ClientNode* pclntNextClient; 

public: 

    // Access methods  
    void setNext(ClientNode* pclndNextNode); 
    void setClient(Client clntNewClient); 
    Client getClient(); 
    ClientNode* getNext(); 

}; 
#endif 
//////////////////////////////////////////////////// 
// ClientNode.cpp 
#include "ClientNode.h" 

/* 
* [Description]: This method sets the next node our node would be pointing add 
* [Paramaters]: 
* pclndNextNode - The address of the next node we want this node to point at 
* [Return Value]: none 
*/ 
void ClientNode::setNext(ClientNode* pclndNextNode) 
{ 
    this->pclntNextClient = pclndNextNode; 
} 

/* 
* [Description]: This method sets the client struct we want our current node to contain 
* [Paramaters]: 
* clntNewClient - New client 
* [Return Value]: none 
*/ 
void ClientNode::setClient(Client clntNewClient) 
{ 
    this->clntClient = clntNewClient; 
} 

/* 
* [Description]: This method returns the client instance our node contains 
* [Paramaters]: none 
* [Return Value]: Our client 
*/ 
Client ClientNode::getClient() 
{ 
    return (this->clntClient); 
} 

/* 
* [Description]: This method returns the next node our node points at 
* [Paramaters]: none 
* [Return Value]: The address of the next node this node is pointing at 
*/ 
ClientNode* ClientNode::getNext() 
{ 
    return (this->pclntNextClient); 
} 
//////////////////////////////////////////////////// 
// Client.h 
#ifndef CLIENT_H 
#define CLIENT_H 
#include <WinSock2.h> 

#define MAX_CLIENT_NAME_LEN = 40 

class Client 
{ 
    // Data members 
    SOCKET scktClientSock; 
    char* szClientName; 
    bool bIsAdmin; 
    int nNameLength; 

    public: 

     // Access methods  
     void setClientSocket(SOCKET scktClientSock); 
     SOCKET getClientSocket(); 
     void setClientName(char* szClientName); 
     char* getClientName(); 
     void setIsAdmin(bool bIsAdmin); 
     bool getIsAdmin(); 
     int getNameLength(); 

     // Other methods 

}; 
#endif 
//////////////////////////////////////////////////// 
// Client.h 
#include "Client.h" 

/* 
* [Description]: This method changes the SOCKET data member of the Client class 
* [Paramaters]: 
* _scktClientSock - the new socket client that is being set 
* [Return Value]: none 
*/ 
void Client::setClientSocket(SOCKET _scktClientSock) 
{ 
    this->scktClientSock = _scktClientSock; 
} 

/* 
* [Description]: This method retrieves the client's socket 
* [Paramaters]: none 
* [Return Value]: The socket client 
*/ 
SOCKET Client::getClientSocket() 
{ 
    return (this->scktClientSock); 
} 

/* 
* [Description]: This method changes the client's name 
* [Paramaters]: 
* _szClientName - a zero terminated string that describes the new client's name 
* [Return Value]: none 
*/ 
void Client::setClientName(char* _szClientName) 
{ 
    // Variable definition 
    int nIndex = -1; 

    // Code section 
    this->szClientName = new char[41]; 

    // Copy string char per char 
    do 
    { 
     ++nIndex; 
     this->szClientName[nIndex] = _szClientName[nIndex]; 
    } while (_szClientName[nIndex] != '\0');  

    // Name length is equal to index 
    this->nNameLength = nIndex; 
} 

/* 
* [Description]: This method returns a pointer to the first char of the zero terminated client string 
* [Paramaters]: none 
* [Return Value]: a pointer to the string 
*/ 
char* Client::getClientName() 
{ 
    return (this->szClientName); 
} 

/* 
* [Description]: This method is used to set whether the client is an admin or not 
* [Paramaters]: 
* _bIsAdmin - a boolean indication of whether the user is an admin or not 
* [Return Value]: none 
*/ 
void Client::setIsAdmin(bool _bIsAdmin) 
{ 
    this->bIsAdmin = _bIsAdmin; 
} 

/* 
* [Description]: This method determines whether the user is an admin or not 
* [Paramaters]: none 
* [Return Value]: A boolean indication of whether the user is an admin or not 
*/ 
bool Client::getIsAdmin() 
{ 
    return (this->bIsAdmin); 
} 

/* 
* [Description]: This method retrieves the client's name length 
* [Paramaters]: none 
* [Return Value]: the name length 
*/ 
int Client::getNameLength() 
{ 
    return (this->nNameLength); 
} 

再次,這是一些很舊的代碼,我已經寫了我道歉,如果它不是那麼好,但它肯定工程...還注意到,我已經包含服務器代碼中的許多不同的模式,每個由以下

//////////////////////////////////////////////////// 
+0

如果您可以發佈您的cpp代碼,它將會有很大的幫助。 –

+0

好的,我會的,現在 – DrPrItay

+0

@DrPrltay謝謝,如果你創建了一個,你能給我makefile嗎?告訴我編譯和運行的命令。直到現在我還沒有處理過多個文件。對不起,打擾了。 –