Socket programming

It is a small prerequisite of reading my blogs on Pattern-Oriented Software Architecture volume-2 book. If you want to read this book, It is even required.

In this blog, I have explained three different scenarios of client-server communication over TCP-IP. I have used windows socket to implement the code.

My intention here is not to discuss the theory of socket programming. I am just giving you a very basic implementation so that you can use this code to learn distributed patterns on a client-server based system on socket programming.

If you are interested in reading the basic theory of socket programming before go ahead, please read this link.


  1. You are sending and receiving one massage at a time.
  2. Sending and receiving one massage at a time
    Please click on the image to see the zoom view.
    • It's the first and most straightforward example where you send a small packet request to the server and wait for its response.
  3. You are sending large files from client to server.
  4. Sending large files from client to server
    Please click on the image to see the zoom view.
    • In case I have MB or GB of data to send from the client to the server. Here I am sending data from the client-side and writing it down to a new file created at the server end.
  5. Multiple clients send messages to the server.
  6. Sending large file from client to server.
    Please click on the image to see the zoom view.
    • It's an interesting one, as there are multiple clients. I am sending request individually at the same time. I have used C++11 multithreading to implement it.

Implementation 

Let's start with the server.

Server socket
Please click on the image to see the zoom view.


SocketAcceptor.h
This class is responsible for setting up the server socket connection.

/***************************************************************************************************
//   Author:    Kunjesh Singh Baghel
//   Web-page:  https://sites.google.com/site/kunjeshsinghbaghel/
***************************************************************************************************/
#ifndef _SOCKET_ACCEPTOR_
#define _SOCKET_ACCEPTOR_
#pragma once

#include <winsock2.h>
#include <memory>
#include <thread>
#include <atomic>
#include "Socket.h"
#include "IMessage.h"

using namespace IO_MSG;
#define MAX_CLIENT 20

namespace SERVER_SOCKET
{
  class SocketAcceptor
  {
  private:
    WSADATA                             windowsSocketsData;
    SOCKET                              serverSocket;
    volatile SOCKET                     clientSocket;
    SOCKADDR_IN                         serverAddress;
    SOCKADDR_IN                         clientAddress;
    USHORT                              sPortNumber;
    bool                                isConnectionSuccess;
    std::shared_ptr<Socket>             sConnect;

    //__________________________For multi-client connection.
    std::atomic<int>                    clientIndex;
    bool                                bStopPooling;
    std::thread                         tClients[MAX_CLIENT];

    bool                                Setup();
    bool                                Bind();
    bool                                Listen();
    bool                                AcceptCleintConnection();

  public:
    /* Constructor */                   SocketAcceptor();
    /* destructor */                    ~SocketAcceptor();
    bool inline                         IsServerSocketCreated() { return isConnectionSuccess; }
    bool                                Accept();
    std::shared_ptr<Socket>             GetSocket();

    //__________________________For multi-client connection.
    /*!
    * Description : This method will create one thread per client connection.
    */
    bool                                MultiClientAccept();
    void                                ClearAcceptThread();
  };
}

#endif // !_SOCKET_ACCEPTOR_


SocketAcceptor.cpp

/***************************************************************************************************
//   Author:    Kunjesh Singh Baghel
//   Web-page:  https://sites.google.com/site/kunjeshsinghbaghel/
***************************************************************************************************/
#ifndef _SOCKET_ACCEPTOR_
#pragma once
// WinAPI indicates to the linker that the Ws2_32.lib file is needed.
#pragma comment(lib,"ws2_32.lib")   

#include "SocketAcceptor.h"
#include "Log.h"
#include "GlobalFactory.h"

#include <windows.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include<iostream>

using namespace SESSION;
using namespace CONFIGURATION_MANAGER;

namespace SERVER_SOCKET
{
  //__________________________For multi-client connection.
  Queue <shared_ptr<IMessage > > Socket::clientRequests;

  SocketAcceptor::SocketAcceptor(): serverSocket(INVALID_SOCKET),
                                    clientSocket(INVALID_SOCKET),
                                    sPortNumber(0),
                                    isConnectionSuccess(false),
                                    sConnect(nullptr),
                                    clientIndex(0),
                                    bStopPooling(false)
  {
    LOG_IT(LOG::SETUP_INFO, "SocketAcceptor Constructor called");
    sPortNumber = std::stoi(FactoryInstance::GetGlobalFactory()->GetConfigurationManager()->GetValue("Port_number", VALUE));
    LOG_IT(LOG::SETUP_INFO, "Port number - %d", sPortNumber);
    if (!Setup())
      return;
    if (!Bind())
      return;
    if (!Listen())
      return;
    sConnect = std::make_shared<Socket>();
    isConnectionSuccess = true;
  }
  SocketAcceptor::~SocketAcceptor()
  {
    LOG_IT(LOG::SETUP_INFO, "Cleanup process : SocketAcceptor getting Closed");
    shutdown(serverSocket, SD_SEND);  // Shutdown our socket
    closesocket(serverSocket);        // Close our socket entirely
    LOG_IT(LOG::SETUP_INFO, "~SocketAcceptor Shutting down the socket");
    shutdown(clientSocket, SD_SEND);
    LOG_IT(LOG::SETUP_INFO, "~SocketAcceptor Shutting server socket");
    WSACleanup();
  }

  bool SocketAcceptor::Setup()
  {
    LOG_IT(LOG::SETUP_INFO, "Starting the setup");
    int rVal = WSAStartup(MAKEWORD(2, 0), &windowsSocketsData);
    if (rVal != 0)
    {
      LOG_IT(LOG::ERROR_MSG, "WSAStartup failed with error %d " , rVal);
      return false;
    }
    serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (serverSocket == INVALID_SOCKET)
    {
      LOG_IT(LOG::ERROR_MSG, "Not able to create server socket, error code is - %d ", WSAGetLastError());
      return false;
    }
    serverAddress.sin_addr.s_addr   = INADDR_ANY;
    serverAddress.sin_family        = AF_INET;
    serverAddress.sin_port          = htons(sPortNumber);
    LOG_IT(LOG::SETUP_INFO, "Server Socket is created ...");
    return true;
  }

  bool SocketAcceptor::Bind()
  {
    LOG_IT(LOG::SETUP_INFO, "Binding initiated ...");
    // if we don't use :: for bind it sees some other bind and gets error, to call global bind we need scoped resolution operator.
    auto iResult = ::bind(serverSocket, (SOCKADDR*)& serverAddress, sizeof(serverAddress)); 
    if (iResult == SOCKET_ERROR)
    {
      LOG_IT(LOG::ERROR_MSG, "bind failed with error - %d ", WSAGetLastError());
      return false;
    }
    LOG_IT(LOG::SETUP_INFO, "Binding Completed ...");
    return true;
  }

  bool SocketAcceptor::Listen()
  {
    LOG_IT(LOG::SETUP_INFO, "Server starts listening ...");
    if (listen(serverSocket, 10) == SOCKET_ERROR)
    {
      LOG_IT(LOG::ERROR_MSG, "Listen failed with error - %d ", WSAGetLastError());
      return false;
    }
    return true;
  }

  void SocketAcceptor::ClearAcceptThread()
  {
    while (clientIndex >= 0)
    {
      if (tClients[clientIndex].joinable())
      {
        tClients[clientIndex].join();
      }
      --clientIndex;
    }
  }

  bool SocketAcceptor::MultiClientAccept()
  {
    while (true)
    {
      if (bStopPooling)
      {
        break;
      }
      if (!AcceptCleintConnection())
        return false;
      tClients[clientIndex] = std::thread(Socket::MultiClientReceiveShortMsg, sConnect.get(), clientSocket);
      ++clientIndex;
      if (clientIndex >= MAX_CLIENT - 2)
      {
        ClearAcceptThread();
      }
    }
    if(clientIndex > 0) // for clean up.
      ClearAcceptThread();
    return true;
  }

  bool SocketAcceptor::Accept()
  {
    if (!AcceptCleintConnection())
      return false;
    sConnect->SetConnectionHandle(clientSocket);
    return true;
  }

  std::shared_ptr<Socket> SocketAcceptor::GetSocket()
  {
    return sConnect;
  }

  bool SocketAcceptor::AcceptCleintConnection()
  {
    int clientAddrSize = sizeof(clientAddress);
    clientSocket = accept(serverSocket, (SOCKADDR*)& clientAddress, &clientAddrSize);
    LOG_IT(LOG::SETUP_INFO, "accepted from client socket - %d", serverSocket);
    if (clientSocket == INVALID_SOCKET)
    {
      LOG_IT(LOG::ERROR_MSG, "accept failed: %d ", WSAGetLastError());
      return false;
    }
    return true;
  }
}

#endif // !_SOCKET_ACCEPTOR_

Socket.h
Once the connection is established. Socket class will send/receive the massages.

/***************************************************************************************************
//   Author:    Kunjesh Singh Baghel
//   Web-page:  https://sites.google.com/site/kunjeshsinghbaghel/
***************************************************************************************************/

#ifndef _SOCKET_H_
#define _SOCKET_H_
// The WIN32_LEAN_AND_MEAN macro prevents the Winsock.h from being included by the Windows.h header
#ifndef WIN32_LEAN_AND_MEAN 
#define WIN32_LEAN_AND_MEAN
#endif
#pragma once

#include <winsock2.h>
#include "Queue.h"
#include "IMessage.h"

using namespace IO_MSG;
using namespace Thread;

namespace SERVER_SOCKET
{
 
  class Socket
  {
  private:
    SOCKET                                      clientSocket;
    USHORT                                      sBufferLen;

    bool                                        Receive(char* buffer, int& byteReceived, SOCKET client, std::shared_ptr<IMessage> pMsg = nullptr);
    size_t                                      Send(const char* msg, SOCKET client);
    //__________________________For multi-client connection.
    static Queue <shared_ptr<IMessage > >       clientRequests;

  public:
    /* Default constructor */                   Socket();
    /* Destructor */                            ~Socket();

    void                                        SetConnectionHandle(SOCKET clientSocket);
    SOCKET                                      GetConnectionHandle();
    bool                                        ReceiveAndLogMessage();
    bool                                        ReceiveShortMsg(std::shared_ptr<IMessage> pMsg = nullptr);
    size_t                                      SendToClient(const char* msg, SOCKET client = 0);

    //__________________________For multi-client connection.
    static bool                                 MultiClientReceiveShortMsg(void *pThis, SOCKET client);
    static Queue <shared_ptr<IMessage > >&      GetClientRequests();
  };
}

#endif // !_SOCKET_H_

Socket.cpp

/***************************************************************************************************
//   Author:    Kunjesh Singh Baghel
//   Web-page:  https://sites.google.com/site/kunjeshsinghbaghel/
***************************************************************************************************/

#include "Socket.h"
#include "Log.h"
#include "GlobalFactory.h"
#include "WriteOnlyFile.h"

using namespace SESSION;
using namespace CONFIGURATION_MANAGER;
using namespace FILE_IO;

char  Buffer[512];
namespace SERVER_SOCKET
{
  Socket::Socket() : clientSocket(INVALID_SOCKET)
  {
    LOG_IT(LOG::SETUP_INFO, "Construction process : server Socket is getting created");
    sBufferLen = std::stoi(FactoryInstance::GetGlobalFactory()->GetConfigurationManager()->GetValue("Buffer_size", VALUE));
  }

  Socket::~Socket()
  {
    LOG_IT(LOG::SETUP_INFO, "Cleanup process : server Socket is getting closed");
  }

  void Socket::SetConnectionHandle(SOCKET clientSocket)
  {
    this->clientSocket = clientSocket;
  }

  SOCKET Socket::GetConnectionHandle()
  {
    return clientSocket;
  }

  bool Socket::ReceiveShortMsg(std::shared_ptr<IMessage> pMsg)
  {
    int byteReceived;
    if (Receive(Buffer, byteReceived, clientSocket, pMsg))
    {
      LOG_IT(LOG::INFO, "Total bytes received from the client is - : %d", byteReceived);
      return true;
    }
    return false;
  }

  bool Socket::MultiClientReceiveShortMsg(void *pThis, SOCKET client)
  {
    Socket* thisPtr = static_cast<Socket*>(pThis);
    char  Buff[512];  // creating local buffer. This will help in multi-threaded environment.
    int byteReceived = 0;
    do
    {
      shared_ptr<IMessage > pMsg = make_shared<Message>();
      if (!thisPtr->Receive(Buff, byteReceived, client, pMsg))
        return false;
      clientRequests.Insert(pMsg);
    } while (byteReceived > 0);
    LOG_IT(LOG::INFO, "Total bytes received from the client is - : %d", byteReceived);
    return true;
  }

  bool Socket::ReceiveAndLogMessage()
  {
    LOG_IT(LOG::SETUP_INFO, "Receiving the client data - ");
    size_t byteReceived = 0;
    int rValue = 0;
    //______________________________________ Large msg need to be dumped at file.
    std::string filePath = FactoryInstance::GetGlobalFactory()->GetFileName();
    filePath = filePath.substr(0, filePath.find_last_of("\\"));
    filePath = filePath + "\\" + to_string(clientSocket) + ".log";
    std::unique_ptr<IWriteOnlyFile> pFile = std::make_unique<WriteOnlyFile>(filePath, DELETE_OLD_CONTENT_ON_EVERY_RELOAD, false);
    do
    {
      Receive(Buffer, rValue, clientSocket);
      pFile->Write(Buffer);
    } while (rValue > 0);
    LOG_IT(LOG::INFO, "Receive message in bytes - %d", byteReceived);
    return true;
  }

  bool Socket::Receive(char* buffer, int& byteReceived, SOCKET client, std::shared_ptr<IMessage> pMsg)
  {
    memset(buffer, 0, sizeof(buffer));
    byteReceived = recv(client, buffer, 512, 0);
    if (byteReceived > 0)
    {
      LOG_IT(LOG::INFO, "Message from the client %d is - : %s", client, buffer);
      if (pMsg != nullptr) // Setting the info into the IMessage buffer class.
      {
        pMsg->SetMsg(string(buffer));
        pMsg->SetFromSocket(to_string(client));
      }
    }
    else if (byteReceived == 0)
    {
      LOG_IT(LOG::ERROR_MSG, " Connection is closed ");
      return false;
    }
    else
    {
      LOG_IT(LOG::ERROR_MSG, "recv failed with error code - : %d", WSAGetLastError());
      return false;
    }
    return true;
  }

  size_t Socket::Send(const char* msg, SOCKET client)
  {
    size_t byteSend = 0;
    LOG_IT(LOG::SETUP_INFO, " Sending data back to the client %d", client);
    memset(Buffer, 0, sizeof(Buffer));
    std::memcpy(Buffer, msg, 512);
    byteSend = send(client, Buffer, sizeof(Buffer), 0);
    if (byteSend == SOCKET_ERROR)
    {
      LOG_IT(LOG::ERROR_MSG, "send failed with error: %d ", WSAGetLastError());
    }
    return byteSend;
  }

  size_t Socket::SendToClient(const char *msg, SOCKET client)
  {
    if (client != 0)
    {
      return Send(msg, client);
    }
    else
    {
      return Send(msg, clientSocket);
    }
  }

  Queue <shared_ptr<IMessage > >& Socket::GetClientRequests()
  {
    return clientRequests;
  }
}

Now come to the client 

Client socket
Please click on the image to see the zoom view.

ConnectSocket.h
This class is responsible for setting up the client socket.

/***************************************************************************************************
//   Author:    Kunjesh Singh Baghel
//   Web-page:  https://sites.google.com/site/kunjeshsinghbaghel/
***************************************************************************************************/

#ifndef _CONNECT_SOCKET_
#define _CONNECT_SOCKET_
#endif // !_CONNECT_SOCKET_

#include <string>
#include <memory>
#include "SendAndReceiveMessages.h"

namespace CLIENT_SOCKET
{
  class ConnectToServer
  {
  private:
    WSADATA                             windowsSocketsData;
    SOCKET                              serverSocket;
    SOCKADDR_IN                         serverAddress;
    std::string                         serverIpAddress;
    USHORT                              sPortNumber;
    bool                                isConnectionSuccess;
    std::shared_ptr<SendAndReceive>     pSendMsg;

    bool                                Setup();

  public:
    /* Default constructor */           ConnectToServer();
    /* Destructor */                    ~ConnectToServer();
    bool                                IsConnected();
    std::shared_ptr<SendAndReceive>     GetSendAndReceive();
    bool                                Connect();
  };
}
#pragma once

ConnectSocket.cpp


/***************************************************************************************************
//   Author:    Kunjesh Singh Baghel
//   Web-page:  https://sites.google.com/site/kunjeshsinghbaghel/
***************************************************************************************************/
#pragma warning(disable:4996) 
#pragma comment(lib,"ws2_32.lib")   // WinAPI indicates to the linker that the Ws2_32.lib file is needed.

#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <windows.h>
#include "ConnectSocket.h"
#include "GlobalFactory.h"
#include "Log.h"

using namespace SESSION;
using namespace CONFIGURATION_MANAGER;

namespace CLIENT_SOCKET
{
  ConnectToServer::ConnectToServer() : isConnectionSuccess(false), pSendMsg(nullptr)
  {
    serverIpAddress = FactoryInstance::GetGlobalFactory()->GetConfigurationManager()->GetValue("IP_Address", VALUE);
    sPortNumber = std::stoi(FactoryInstance::GetGlobalFactory()->GetConfigurationManager()->GetValue("Port_number", VALUE));
    if (!Setup())
    {
      LOG_IT(LOG::ERROR_MSG, "ConnectToServer Setup failed ");
      return;
    }
    if (!Connect())
    {
      LOG_IT(LOG::ERROR_MSG, "ConnectToServer Connect failed ");
      return;
    }
    pSendMsg.reset(new SendAndReceive(serverSocket));
    isConnectionSuccess = true;

  }

  ConnectToServer::~ConnectToServer()
  {
    LOG_IT(LOG::SETUP_INFO, "Cleanup process : ConnectToServer client socket is getting cleaned up");
  }

  bool ConnectToServer::IsConnected()
  {
    return isConnectionSuccess; 
  }

  std::shared_ptr<SendAndReceive>  ConnectToServer::GetSendAndReceive()
  {
    return pSendMsg;
  }

  bool ConnectToServer::Setup()
  {
    int rVal = WSAStartup(MAKEWORD(2, 0), &windowsSocketsData);
    if (rVal != 0)
    {
      LOG_IT(LOG::ERROR_MSG, "Initialization of Windows Sockets Data failed -  %d ", rVal);
      return false;
    }
    serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (serverSocket == INVALID_SOCKET)
    {
      LOG_IT(LOG::ERROR_MSG, "Error at socket()  -  %d ", WSAGetLastError());
      return false;
    }
    serverAddress.sin_addr.s_addr = inet_addr(serverIpAddress.c_str());
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port = htons(sPortNumber);
    LOG_IT(LOG::SETUP_INFO, "Server Socket is created ... ");
    return true;
  }

  bool ConnectToServer::Connect()
  {
    auto rVal = connect(serverSocket, (SOCKADDR*)& serverAddress, sizeof(serverAddress));
    if (rVal == SOCKET_ERROR)
    {
      LOG_IT(LOG::ERROR_MSG, "connect failed with error code -  %d ", WSAGetLastError());
      return false;
    }
    LOG_IT(LOG::SETUP_INFO, "Connected to the server socket - %d ", serverSocket);
    return true;
  }
}


SendAndReceiveMessages.h
Once the connection is established. it will send/receive the massages.


/***************************************************************************************************
//   Author:    Kunjesh Singh Baghel
//   Web-page:  https://sites.google.com/site/kunjeshsinghbaghel/
***************************************************************************************************/

#ifndef _SEND_AND_RECEIVE_MESSAGES_
#define _SEND_AND_RECEIVE_MESSAGES_

#ifndef WIN32_LEAN_AND_MEAN // The WIN32_LEAN_AND_MEAN macro prevents the Winsock.h from being included by the Windows.h header
#define WIN32_LEAN_AND_MEAN
#endif

#pragma once

#include <winsock2.h>

namespace CLIENT_SOCKET
{
  class SendAndReceive
  {
  private:
    SOCKET                                serverSocket;
    USHORT                                sBufferLen;

  public:
    /* Default constructor */             SendAndReceive(SOCKET socket);
    /* Destructor */                      ~SendAndReceive();
    void                                  Send(const char *msg);
    bool                                  Receive();
  };
}
#endif // !_SEND_AND_RECEIVE_MESSAGES_

SendAndReceiveMessages.cpp

/***************************************************************************************************
//   Author:    Kunjesh Singh Baghel
//   Web-page:  https://sites.google.com/site/kunjeshsinghbaghel/
***************************************************************************************************/

#include "SendAndReceiveMessages.h"
#include "Log.h"
#include "GlobalFactory.h"

using namespace SESSION;
using namespace CONFIGURATION_MANAGER;

namespace CLIENT_SOCKET
{
  SendAndReceive::SendAndReceive(SOCKET socket) : serverSocket(socket)
  {
    LOG_IT(LOG::SETUP_INFO, "Construction process : SendAndReceive client socket is getting created");
    sBufferLen = std::stoi(FactoryInstance::GetGlobalFactory()->GetConfigurationManager()->GetValue("Buffer_size", VALUE));
  }

  SendAndReceive::~SendAndReceive()
  {
    LOG_IT(LOG::SETUP_INFO, "Cleanup process : SendAndReceive client socket is getting cleaned up");
  }

  void SendAndReceive::Send(const char* msg)
  {
    char Buffer[512];       // creating local buffer. This will help in multi-threaded environment.
    memset(Buffer, 0, sizeof(Buffer));
    std::memcpy(Buffer, msg, 512);
    size_t byteSend = send(serverSocket, Buffer, sizeof(Buffer), 0);
    if (byteSend == SOCKET_ERROR)
    {
      LOG_IT(LOG::ERROR_MSG, "send failed with error: %d ", WSAGetLastError());
    }
    LOG_IT(LOG::INFO, "Message sent! %s", Buffer);
  }

  bool SendAndReceive::Receive()
  {
    char Buffer[512];
    memset(Buffer, 0, sizeof(Buffer));
    auto rVal = recv(serverSocket, Buffer, sizeof(Buffer), 0);
    if (rVal == SOCKET_ERROR)
    {
      LOG_IT(LOG::ERROR_MSG, "send failed with error code - %d " , WSAGetLastError());
      return false;
    }
    LOG_IT(LOG::INFO, "Received value is - %s", Buffer);
    return true;
  }
}

Invoke the client and server-side DLLs


  1. You are sending and receiving one massage at a time.
    • Code example
    • //____________________________Client side
      
      void SendShortMessage()
      {
        std::unique_ptr<ConnectToServer> pConnect = std::make_unique<ConnectToServer>();
        if (pConnect->IsConnected())
        {
          std::shared_ptr<SendAndReceive> pServer = pConnect->GetSendAndReceive();
          pServer->Send("Ping server request-1");
          pServer->Receive();
      
          this_thread::sleep_for(chrono::seconds(2));
      
          pServer->Send("Ping server request-2");
          pServer->Receive();
      
          this_thread::sleep_for(chrono::seconds(2));
      
          pServer->Send("Ping server request-3");
          pServer->Receive();
        }
        else
        {
          LOG_IT(LOG::ERROR_MSG, "Connection to server has not been created properly");
        }
      }//____________________________Server side
      void SmallMsg()
      {
        std::unique_ptr<SocketAcceptor> pConnect = std::make_unique<SocketAcceptor>();
        if (pConnect->IsServerSocketCreated())
        {
          pConnect->Accept();
          std::shared_ptr<Socket> pSocket = pConnect->GetSocket();
          int response = 0;
          string response_msg;
          while (pSocket->ReceiveShortMsg())
          {
            ++response;
            response_msg = "Sending data back to client" + std::to_string(response);
            pSocket->SendToClient(response_msg.c_str());
          }
        }
        else
        {
          LOG_IT(ERROR_MSG, "Opening server connection failed");
        }
      }
      
  2. You are sending large files from client to server.
    • Code example
    • //____________________________Client side
      
      void SendLargeMessage()
      {
        std::string filePath = FactoryInstance::GetGlobalFactory()->GetFileName();
        filePath = filePath.substr(0, filePath.find_last_of("\\"));
        filePath += "\\ClientTestFile.txt";
        unique_ptr<ifstream> pFile = make_unique<ifstream>();
        pFile->open(filePath);
        if (!pFile->is_open())
        {
          LOG_IT(ERROR_MSG, "Not able to load the file");
        }
        std::unique_ptr<ConnectToServer> pConnect = std::make_unique<ConnectToServer>();
        if (pConnect->IsConnected())
        {
          string line;
          std::shared_ptr<SendAndReceive> pServer = pConnect->GetSendAndReceive();
          while (std::getline(*pFile, line))
          {
            pServer->Send(line.c_str());
          }
        }
        else
        {
          LOG_IT(LOG::ERROR_MSG, "Connection to server has not been created properly");
        }
      }
      
      //____________________________Server side
      
      
      void LargeMsg()
      {
        std::unique_ptr<SocketAcceptor> pConnect = std::make_unique<SocketAcceptor>();
        if (pConnect->IsServerSocketCreated())
        {
          pConnect->Accept();
          std::shared_ptr<Socket> pSocket = pConnect->GetSocket();
          while (pSocket->ReceiveAndLogMessage())
          {
            pSocket->SendToClient("Logged all the data");
          }
        }
        else
        {
          LOG_IT(ERROR_MSG, "Opening server connection failed");
        }
      }
      
  3. Multiple clients send messages to the server.
    • Code example 
    • //____________________________Client side
      void Client_A()
      {
        std::unique_ptr<ConnectToServer> pConnect = std::make_unique<ConnectToServer>();
        if (pConnect->IsConnected())
        {
          std::shared_ptr<SendAndReceive> pServer = pConnect->GetSendAndReceive();
          pServer->Send("Client_A | Order X ");
          pServer->Receive();
      
          pServer->Send("Client_A | Order Y ");
          pServer->Receive();
      
          pServer->Send("Client_A | Order Z ");
          pServer->Receive();
        }
        else
        {
          LOG_IT(INFO, "Connection to server has not been created properly ");
        }
      }
      
      void Client_B()
      {
        std::unique_ptr<ConnectToServer> pConnect = std::make_unique<ConnectToServer>();
        if (pConnect->IsConnected())
        {
          std::shared_ptr<SendAndReceive> pServer = pConnect->GetSendAndReceive();
          pServer->Send("Client_B | Order 1 ");
          pServer->Receive();
      
          pServer->Send("Client_B | Order 2 ");
          pServer->Receive();
      
          pServer->Send("Client_B | Order 3 ");
          pServer->Receive();
        }
        else
        {
          LOG_IT(INFO, "Connection to server has not been created properly ");
        }
      }
      
      void Client_C()
      {
        std::unique_ptr<ConnectToServer> pConnect = std::make_unique<ConnectToServer>();
        if (pConnect->IsConnected())
        {
          std::shared_ptr<SendAndReceive> pServer = pConnect->GetSendAndReceive();
          pServer->Send("Client_C | Order One ");
          pServer->Receive();
      
          pServer->Send("Client_C | Order Two ");
          pServer->Receive();
      
          pServer->Send("Client_C | Order Three ");
          pServer->Receive();
        }
        else
        {
          LOG_IT(INFO, "Connection to server has not been created properly ");
        }
      }
      
      void MultiClientTest()
      {
        thread T1(Client_A);
        thread T2(Client_B);
        thread T3(Client_C);
      
        T1.join();
        T2.join();
        T3.join();
      }
      
      //____________________________Server side
      
      
      void ProcessMultiClientRequest(std::shared_ptr<Socket> pSocket)
      {
        Queue <shared_ptr<IMessage > >& Q = Socket::GetClientRequests();
        while (true)
        {
          std::unique_lock<std::mutex> lockIt(Q.GetMutex());
          Q.GetNotified().wait(lockIt, [&]() {return  !Q.IsEmpty(); });
          shared_ptr<IMessage > msg = Q.Front();
          Q.Remove();
          string responce = msg->GetMsg();
          responce = "Your Order " + responce + "is placed ";
          pSocket->SendToClient(responce.c_str(), std::stoi(msg->GetClientSocket()));
        }
      }
      
      void MultiClient()
      {
        std::unique_ptr<SocketAcceptor> pConnect = std::make_unique<SocketAcceptor>();
        if (pConnect->IsServerSocketCreated())
        {
          std::shared_ptr<Socket> pSocket = pConnect->GetSocket();
          std::thread processThread(ProcessMultiClientRequest, pSocket);
          pConnect->MultiClientAccept();
          processThread.join();
        }
        else
        {
          LOG_IT(ERROR_MSG, "Opening server connection failed");
        }
      }
      


Thanks for reading it. To learn more about design patterns and basic design principles, please see my web page.

Comments

Popular posts from this blog

Non-virtual interface idiom (NVI)

Factory method design pattern for beginners.

Architectural patterns => Mud to structure => layers.