我可以通过服务器之间实现客户端 - 客户端通信吗?

时间:2016-08-13 06:43:29

标签: c sockets client-server

我想通过此服务器从客户端A向客户端B发送消息。我不知道怎么能得到那个?我能想到的一种方法是为每个客户端创建一个消息队列,如果有人向该客户端发送消息,并从该队列发送到相应的客户端,则向该队列添加消息?但我不确定如何实现这一点?任何人都可以帮我这个吗?

任何时候都可以有n个客户。在这种情况下,向所有客户广播。

以下是我的服务器代码。我检查了用户的用户名和密码。 insidePortal()函数将负责向其他客户端发送消息。

#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]) {

}

1 个答案:

答案 0 :(得分:2)

我有这个很长的代码,我以前编写的代码实现了类似于你的东西,但它是CPP,如果你也想我会在这里发布,但基本上使用消息队列或多进程编程似乎有点对我没用,如果我是你,我会按照以下方式编程

客户代码 - &gt;两个主题 服务器代码 - &gt;两个主题

Client有两个主题和三个函数,Connect / Send / Receive

  • Connect - 此函数处理与服务器的连接,无论您是使用TCP还是处理listen-accept,或者如果您使用某些基于UDP的组成协议,它只是处理它 - 确保您有一些连接< / LI>
  • Send - 此函数将一些数据发送到服务器
  • Receive此functino从服务器接收数据

Client的流程如下:

  1. Client连接到Main thread
  2. 上的服务器
  3. 连接到服务器Client后创建Second thread
  4. 开启Main thread - Client进入一个循环,从用户读取数据作为输入然后调用Send函数并将其发送到服务器
  5. 点击Second thread - Client进入一个调用Receive的循环 从服务器接收数据并在收到数据时打印数据
  6. 处理Client,现在约为Server

    Server - 有三个函数和一个名为Linked - List的全局数据结构(显然是一个链接列表),它将被所有线程共享,WaitForConnection Receive {{1 }}

    • SendToAll - 简单地调用套接字API的“接受”功能(如果你使用的是TCP)或者如果你正在使用其他一些组成的协议,这个函数只是阻止它的线程试图等待传入连接,当某个连接到达时,此函数将连接注册到名为WaitForConnection的所有连接的全局链表中,并使用适当的套接字和客户端数据
    • Connection-List - 只需迭代所有SendToAll,并为该列表中的每个连接,它发送一些传递的数据
    • Connection-List只是接收了一些数据但是先设置了一些超时,这对于接收不要阻塞太长时间非常重要!

    Receive的流程如下:

    1. Server creats Main thread
    2. Second thread进入某个循环并在其中调用Main thread,以便不断获取连接并将其添加到WaitForConnection
    3. Connection-List进入迭代Second thread的循环,对于Connection-List内的每个连接,在相应的套接字上调用receive,如果收到某些数据,Connection-List为用接收到的数据调用,如果超时,则没有任何反应,继续循环并执行下一个循环迭代
      1. SendToAll将数据发送给SendToAll
      2. 内的所有客户
    4. 这是一个非常简单的带服务器的多客户端广播架构它应该非常容易实现!我希望这可以帮助你

      我提前道歉,因为这是我前一段时间写过的代码所以它里面有很多嵌套,还有很多评论!

      -------------------------客户端代码---------------- < /强>

      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;
              }
          }
      }
      

      再次这是一些非常古老的代码我写道我道歉如果它不是那么好但它肯定有效...还注意到我在服务器代码中包含许多不同的模型,每个模型由以下分隔< / p>

      // 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);
      }