Skip to content

Instantly share code, notes, and snippets.

@sunmeat
Created March 5, 2026 06:20
Show Gist options
  • Select an option

  • Save sunmeat/91ad1179063fa795618cfe05989ce39e to your computer and use it in GitHub Desktop.

Select an option

Save sunmeat/91ad1179063fa795618cfe05989ce39e to your computer and use it in GitHub Desktop.
OOP TCP + OOP-threads: SERVER SIDE MacOS version
#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