Created
March 5, 2026 06:20
-
-
Save sunmeat/91ad1179063fa795618cfe05989ce39e to your computer and use it in GitHub Desktop.
OOP TCP + OOP-threads: SERVER SIDE MacOS version
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <iostream> | |
| #include <unistd.h> // close(), sleep() | |
| #include <sys/socket.h> | |
| #include <netinet/in.h> | |
| #include <arpa/inet.h> | |
| #include <thread> | |
| #include <string> | |
| #include <memory> // std::unique_ptr | |
| #include <cstring> // memset | |
| using namespace std; | |
| constexpr int DEFAULT_BUFLEN = 512; | |
| constexpr int DEFAULT_PORT = 27015; | |
| constexpr int PAUSE_MS = 1; // в мілісекундах | |
| class TcpServer { | |
| private: | |
| int listenSocket = -1; | |
| int clientSocket = -1; | |
| struct sockaddr_in address {}; | |
| public: | |
| ~TcpServer() { | |
| if (clientSocket != -1) close(clientSocket); | |
| if (listenSocket != -1) close(listenSocket); | |
| } | |
| bool initialize() { | |
| // створюємо сокет | |
| listenSocket = socket(AF_INET, SOCK_STREAM, 0); | |
| if (listenSocket == -1) { | |
| cerr << "Не вдалося створити сокет: " << strerror(errno) << "\n"; | |
| return false; | |
| } | |
| // дозволяємо повторне використання порту одразу після закриття | |
| int opt = 1; | |
| setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); | |
| // заповнюємо адресу | |
| address.sin_family = AF_INET; | |
| address.sin_addr.s_addr = INADDR_ANY; // 0.0.0.0 | |
| address.sin_port = htons(DEFAULT_PORT); | |
| // прив'язуємо | |
| if (bind(listenSocket, (struct sockaddr*)&address, sizeof(address)) < 0) { | |
| cerr << "bind() впала: " << strerror(errno) << "\n"; | |
| return false; | |
| } | |
| // слухаємо | |
| if (listen(listenSocket, SOMAXCONN) < 0) { | |
| cerr << "listen() впала: " << strerror(errno) << "\n"; | |
| return false; | |
| } | |
| cout << "Сервер запущено на порту " << DEFAULT_PORT << " ...\n"; | |
| cout << "Очікую підключення...\n"; | |
| // приймаємо клієнта (блокує) | |
| socklen_t addrlen = sizeof(address); | |
| clientSocket = accept(listenSocket, (struct sockaddr*)&address, &addrlen); | |
| if (clientSocket < 0) { | |
| cerr << "accept() впала: " << strerror(errno) << "\n"; | |
| return false; | |
| } | |
| char client_ip[INET_ADDRSTRLEN]; | |
| inet_ntop(AF_INET, &address.sin_addr, client_ip, INET_ADDRSTRLEN); | |
| cout << "Підключився клієнт: " << client_ip << ":" << ntohs(address.sin_port) << "\n"; | |
| return true; | |
| } | |
| void sender() { | |
| while (true) { | |
| string message; | |
| cout << "Введіть повідомлення для клієнта: "; | |
| getline(cin, message); | |
| if (message.empty()) continue; | |
| ssize_t sent = send(clientSocket, message.c_str(), message.size(), 0); | |
| if (sent < 0) { | |
| cerr << "send() впала: " << strerror(errno) << "\n"; | |
| return; | |
| } | |
| usleep(PAUSE_MS * 1000); // мікросекунди | |
| } | |
| } | |
| void receiver() { | |
| char recvbuf[DEFAULT_BUFLEN]; | |
| while (true) { | |
| ssize_t bytes = recv(clientSocket, recvbuf, DEFAULT_BUFLEN - 1, 0); | |
| if (bytes > 0) { | |
| recvbuf[bytes] = '\0'; | |
| cout << "\nКлієнт пише: " << recvbuf << "\n"; | |
| } | |
| else if (bytes == 0) { | |
| cout << "\nКлієнт від'єднався.\n"; | |
| return; | |
| } | |
| else { | |
| cerr << "\nrecv() впала: " << strerror(errno) << "\n"; | |
| return; | |
| } | |
| usleep(PAUSE_MS * 1000); | |
| } | |
| } | |
| void run() { | |
| thread sendThread(&TcpServer::sender, this); | |
| thread receiveThread(&TcpServer::receiver, this); | |
| // чекаємо завершення потоків | |
| sendThread.join(); | |
| receiveThread.join(); | |
| } | |
| }; | |
| int main() { | |
| setlocale(LC_ALL, "uk_UA.UTF-8"); | |
| // можна залишити або прибрати, залежить від терміналу | |
| // system("clear"); // або printf("\033[2J\033[H"); | |
| cout << "СЕРВЕРНА СТОРОНА\n\n"; | |
| auto server = make_unique<TcpServer>(); | |
| if (!server->initialize()) { | |
| cerr << "Не вдалося ініціалізувати сервер.\n"; | |
| return 1; | |
| } | |
| server->run(); | |
| cout << "Сервер завершив роботу.\n"; | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment