Zgragselus

Server-side

Dec 18th, 2025
133
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.67 KB | None | 0 0
  1. #ifndef __NETWORK_SERVER_TCP__H__
  2. #define __NETWORK_SERVER_TCP__H__
  3.  
  4. #include "../Network.h"
  5.  
  6. namespace Engine
  7. {
  8.     class ServerTcp
  9.     {
  10.     private:
  11.         Network* mNetwork;
  12.  
  13.         int mPort;
  14.         Network::Socket mListenSocket;
  15.  
  16. #ifdef _WIN32
  17.         struct Context
  18.         {
  19.             WSAOVERLAPPED mOverlapped;
  20.             Network::Socket mClientSocket;
  21.             char mBuffer[1024];
  22.             WSABUF mWsaBuffer;
  23.             int mOperationType;
  24.         };
  25.  
  26.         HANDLE mCompletionPort;
  27.         std::thread mWorkerThread;
  28.         std::atomic<bool> mWorkerRunning;
  29. #else
  30.         size_t mMaxEvents;
  31.         epoll_event* mEvents;
  32.         int mEpollFd;
  33. #endif
  34.  
  35.         bool Setup()
  36.         {
  37. #ifdef _WIN32
  38.             // Create IO completion port
  39.             mCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
  40. #endif
  41.  
  42.             // Setup listening socket
  43.             mListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  44.             if (!IS_VALID_SOCKET(mListenSocket))
  45.             {
  46.                 mNetwork->GetLog()->Print("Network.Server.TCP",
  47.                     std::string("Error: Could not create TCP socket: ") + mNetwork->GetLastError());
  48.                 return false;
  49.             }
  50.  
  51. #ifndef _WIN32
  52.             fcntl(mListenSocket, F_SETFL, fcntl(mListenSocket, F_GETFL, 0) | O_NONBLOCK);
  53.  
  54.             int opt = 1;
  55.             setsockopt(mListenSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
  56. #endif
  57.  
  58.             sockaddr_in addr;
  59.             addr.sin_family = AF_INET;
  60.             addr.sin_addr.s_addr = INADDR_ANY;
  61.             addr.sin_port = htons((unsigned short)(mPort));
  62.  
  63.             int result = bind(mListenSocket, (sockaddr*)&addr, sizeof(addr));
  64.             if (result == SOCKET_ERROR)
  65.             {
  66.                 mNetwork->GetLog()->Print("Network.Server.TCP",
  67.                     std::string("Error: Could not bind TCP socket to port ") + std::to_string(mPort) + ": " + mNetwork->GetLastError());
  68.                 CLOSE_SOCKET(mListenSocket);
  69.                 return false;
  70.             }
  71.  
  72.             result = listen(mListenSocket, SOMAXCONN);
  73.             if (result == SOCKET_ERROR)
  74.             {
  75.                 mNetwork->GetLog()->Print("Network.Server.TCP",
  76.                     std::string("Error: Could not listen on TCP socket: ") + mNetwork->GetLastError());
  77.                 CLOSE_SOCKET(mListenSocket);
  78.                 return false;
  79.             }
  80.  
  81.             return true;
  82.         }
  83.  
  84.         void HandleNewConnection()
  85.         {
  86. #ifdef _WIN32
  87.             Network::Socket clientSocket = accept(mListenSocket, NULL, NULL);
  88.             if (IS_VALID_SOCKET(clientSocket))
  89.             {
  90.                 mNetwork->GetLog()->Print("Network.Server.TCP", "Info: New client connected");
  91.  
  92.                 CreateIoCompletionPort((HANDLE)clientSocket, mCompletionPort, 0, 0);
  93.                 PostRead(clientSocket);
  94.             }
  95. #else
  96.             sockaddr_in clientAddr;
  97.             socklen_t clientAddrLen = sizeof(clientAddr);
  98.             Network::Socket clientSocket = accept(mListenSocket, (sockaddr*)&clientAddr, &clientAddrLen);
  99.  
  100.             if (IS_VALID_SOCKET(clientSocket))
  101.             {
  102.                 mNetwork->GetLog()->Print("Network.Server.TCP", "Info: New client connected");
  103.  
  104.                 // Set non-blocking
  105.                 fcntl(clientSocket, F_SETFL, fcntl(clientSocket, F_GETFL, 0) | O_NONBLOCK);
  106.  
  107.                 // Add client to epoll list
  108.                 epoll_event event;
  109.                 event.events = EPOLLIN | EPOLLET;
  110.                 event.data.fd = clientSocket;
  111.                 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, clientSocket, &event);
  112.             }
  113. #endif
  114.         }
  115.  
  116.         void HandleClientData(Network::Socket fd, void* contextPtr, size_t bufferSize)
  117.         {
  118. #ifdef _WIN32
  119.             Context* context = (Context*)contextPtr;
  120.  
  121.             send(fd, context->mBuffer, bufferSize, 0);
  122. #else
  123.             char buffer[1024];
  124.             size_t bytes = recv(fd, buffer, sizeof(buffer), 0);
  125.  
  126.             if (bytes <= 0)
  127.             {
  128.                 mNetwork->GetLog()->Print("Network.Server.TCP.Worker", "Info: Client Disconnected");
  129.                 eopll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
  130.                 close(fd);
  131.             }
  132.             else
  133.             {
  134.                 send(fd, buffer, bytes, 0);
  135.             }
  136. #endif
  137.         }
  138.  
  139. #ifdef _WIN32
  140.         void PostRead(Network::Socket client)
  141.         {
  142.             Context* context = new Context();
  143.             ZeroMemory(&context->mOverlapped, sizeof(WSAOVERLAPPED));
  144.             context->mClientSocket = client;
  145.             context->mWsaBuffer.buf = context->mBuffer;
  146.             context->mWsaBuffer.len = sizeof(context->mBuffer);
  147.             context->mOperationType = 0;
  148.  
  149.             DWORD flags = 0;
  150.             DWORD bytesRead = 0;
  151.             WSARecv(client,
  152.                 &context->mWsaBuffer,
  153.                 1,
  154.                 &bytesRead,
  155.                 &flags,
  156.                 &context->mOverlapped,
  157.                 NULL);
  158.         }
  159.  
  160.         void WorkerThreadProc()
  161.         {
  162.             DWORD bytesTransferred;
  163.             ULONG_PTR completionKey;
  164.             LPOVERLAPPED overlapped;
  165.  
  166.             while (mWorkerRunning)
  167.             {
  168.                 BOOL result = GetQueuedCompletionStatus(
  169.                     mCompletionPort,
  170.                     &bytesTransferred,
  171.                     &completionKey,
  172.                     &overlapped,
  173.                     INFINITE);
  174.  
  175.                 Context* context = (Context*)overlapped;
  176.  
  177.                 if (!result || bytesTransferred == 0)
  178.                 {
  179.                     mNetwork->GetLog()->Print("Network.Server.TCP.Worker", "Info: Client Disconnected");
  180.                     delete context;
  181.                     continue;
  182.                 }
  183.  
  184.                 HandleClientData(context->mClientSocket, context, bytesTransferred);
  185.  
  186.                 // Re-post the read request to keep listening
  187.                 PostRead(context->mClientSocket);
  188.                 // TODO: Use memory pool instead of allocating/deallocating every time
  189.                 delete context;
  190.             }
  191.         }
  192. #endif
  193.  
  194.     public:
  195.         ServerTcp(Network* network, int port, size_t poolSize) :
  196.             mNetwork(network),
  197.             mPort(port),
  198.             mListenSocket(INVALID_SOCKET)
  199.         {
  200. #ifdef _WIN32
  201.             mCompletionPort = NULL;
  202.             mWorkerRunning = false;
  203. #else
  204.             mMaxSize = poolSize;
  205.             mEvents = new epoll_event[mMaxSize];
  206.             mEpollFd = NULL;
  207. #endif
  208.         }
  209.  
  210.         ~ServerTcp()
  211.         {
  212.             if (IS_VALID_SOCKET(mListenSocket))
  213.             {
  214.                 CLOSE_SOCKET(mListenSocket);
  215.             }
  216.  
  217. #ifndef _WIN32
  218.             if (mEvents)
  219.             {
  220.                 delete[] mEvents;
  221.             }
  222. #endif
  223.         }
  224.  
  225.         void Start()
  226.         {
  227.             if (!Setup())
  228.             {
  229.                 return;
  230.             }
  231.  
  232. #ifdef _WIN32
  233.             mWorkerRunning = true;
  234.             mWorkerThread = std::thread(&ServerTcp::WorkerThreadProc, this);
  235. #else
  236.             mEpollFd = epoll_create1(0);
  237.             if (mEpollFd == -1)
  238.             {
  239.                 mNetwork->GetLog()->Print("Network.Server.TCP",
  240.                     std::string("Error: Could not create epoll instance: ") + mNetwork->GetLastError());
  241.                 return;
  242.             }
  243.  
  244.             epoll_event event;
  245.             event.events = EPOLLIN;
  246.             event.data.fd = mListenSocket;
  247.             if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mListenSocket, &event) == -1)
  248.             {
  249.                 mNetwork->GetLog()->Print("Network.Server.TCP",
  250.                     std::string("Error: Could not add listening socket to epoll instance: ") + mNetwork->GetLastError());
  251.                 return;
  252.             }
  253. #endif
  254.         }
  255.  
  256.         void Stop()
  257.         {
  258. #ifdef _WIN32
  259.             mWorkerRunning = false;
  260.             if (mWorkerThread.joinable())
  261.             {
  262.                 mWorkerThread.join();
  263.             }
  264. #else
  265.             if (mEpollFd)
  266.             {
  267.                 CLOSE_SOCKET(mEpollFd);
  268.             }
  269. #endif
  270.         }
  271.  
  272.         void Process()
  273.         {
  274. #ifdef _WIN32
  275.             HandleNewConnection();
  276. #else
  277.             int noFDs = epoll_wait(mEpollFd, mEvents, (int)mMaxSize, -1);
  278.  
  279.             for (int i = 0; i < noFDs; i++)
  280.             {
  281.                 if (mEvents[i].data.fd == mListenSocket)
  282.                 {
  283.                     HandleNewConnection()
  284.                 }
  285.                 else
  286.                 {
  287.                     HandleClientData(mEvents[i].data.fd, NULL, 0);
  288.                 }
  289.             }
  290. #endif
  291.         }
  292.     };
  293. }
  294.  
  295. #endif
Advertisement
Add Comment
Please, Sign In to add comment