Skip to content

Instantly share code, notes, and snippets.

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

  • Save sunmeat/22a6eb662b612c638ee9205e7fd769e0 to your computer and use it in GitHub Desktop.

Select an option

Save sunmeat/22a6eb662b612c638ee9205e7fd769e0 to your computer and use it in GitHub Desktop.
OOP TCP + OOP threads: CLIENT SIDE MacOS version
#include <iostream>
#include <unistd.h> // close(), usleep()
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <thread>
#include <atomic>
#include <string>
#include <cstring> // strerror, memset
#include <netdb.h> // getaddrinfo
using namespace std;
constexpr int DEFAULT_BUFLEN = 512;
constexpr int DEFAULT_PORT = 27015;
constexpr int PAUSE_MS = 1; // мілісекунди
class TcpClient {
private:
int sockfd = -1;
atomic<bool> running{true};
bool createAndConnect(const char* ip, int port) {
struct addrinfo hints{};
struct addrinfo* result = nullptr;
hints.ai_family = AF_UNSPEC; // IPv4 або IPv6
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
string port_str = to_string(port);
if (getaddrinfo(ip, port_str.c_str(), &hints, &result) != 0) {
cerr << "getaddrinfo() помилка: " << gai_strerror(errno) << "\n";
return false;
}
bool connected = false;
for (auto* ptr = result; ptr != nullptr; ptr = ptr->ai_next) {
sockfd = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (sockfd == -1) {
cerr << "socket() помилка: " << strerror(errno) << "\n";
continue;
}
if (connect(sockfd, ptr->ai_addr, ptr->ai_addrlen) == 0) {
connected = true;
break;
}
cerr << "connect() не вдався: " << strerror(errno) << "\n";
close(sockfd);
sockfd = -1;
}
freeaddrinfo(result);
if (!connected) {
cerr << "Не вдалося підключитися до сервера " << ip << ":" << port << "\n";
return false;
}
char host[NI_MAXHOST];
char serv[NI_MAXSERV];
getnameinfo((struct sockaddr*)result->ai_addr, result->ai_addrlen,
host, sizeof(host), serv, sizeof(serv), 0);
cout << "Підключено до " << host << " (" << ip << ":" << port << ")\n";
return true;
}
void sender() {
while (running) {
string message;
cout << "Введіть повідомлення для сервера: ";
getline(cin, message);
if (message.empty()) continue;
ssize_t sent = send(sockfd, message.c_str(), message.size(), 0);
if (sent < 0) {
cerr << "send() помилка: " << strerror(errno) << "\n";
running = false;
break;
}
cout << "Надіслано: " << message << "\n";
usleep(PAUSE_MS * 1000);
}
}
void receiver() {
char buffer[DEFAULT_BUFLEN];
while (running) {
ssize_t bytes = recv(sockfd, buffer, DEFAULT_BUFLEN - 1, 0);
if (bytes > 0) {
buffer[bytes] = '\0';
cout << "\nПовідомлення від сервера: " << buffer << "\n";
}
else if (bytes == 0) {
cout << "\nСервер закрив з'єднання.\n";
running = false;
break;
}
else {
cerr << "recv() помилка: " << strerror(errno) << "\n";
running = false;
break;
}
usleep(PAUSE_MS * 1000);
}
}
public:
~TcpClient() {
if (sockfd != -1) {
shutdown(sockfd, SHUT_RDWR);
close(sockfd);
}
}
bool start(const char* ip = "127.0.0.1", int port = DEFAULT_PORT) {
if (!createAndConnect(ip, port)) {
return false;
}
thread senderThread(&TcpClient::sender, this);
thread receiverThread(&TcpClient::receiver, this);
senderThread.join();
receiverThread.join();
return true;
}
};
int main() {
setlocale(LC_ALL, "uk_UA.UTF-8");
cout << "КЛІЄНТСЬКА СТОРОНА\n";
cout << "-------------------\n\n";
TcpClient client;
// можна змінити IP та порт, наприклад:
// client.start("192.168.1.100", 27015);
if (!client.start("127.0.0.1", DEFAULT_PORT)) {
cerr << "Не вдалося запустити клієнт.\n";
return 1;
}
cout << "Клієнт завершив роботу.\n";
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment