Skip to content

Instantly share code, notes, and snippets.

@sunmeat
Created March 27, 2026 09:04
Show Gist options
  • Select an option

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

Select an option

Save sunmeat/c2c2f4cf7e5b11b8f728462dcdcbb4ca to your computer and use it in GitHub Desktop.
one server multiple clients C++ example (UDP) mac os version
SERVER SIDE:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#include <cstdio>
using namespace std;
#define MAX_CLIENTS 10
#define DEFAULT_BUFLEN 4096
#define PORT 8888
int server_socket;
vector<string> history;
vector<sockaddr_in> clients;
int main() {
cout << "Запуск UDP сервера...\n";
// Створення UDP сокета
if ((server_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("Не вдалося створити сокет");
return 1;
}
sockaddr_in server_addr{};
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
// Прив'язка
if (bind(server_socket, (sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
perror("Помилка bind");
close(server_socket);
return 2;
}
cout << "Сервер запущено на порту " << PORT << ". Очікування клієнтів...\n";
fd_set readfds;
char buffer[DEFAULT_BUFLEN];
sockaddr_in client_addr{};
socklen_t addrlen = sizeof(client_addr);
while (true) {
FD_ZERO(&readfds);
FD_SET(server_socket, &readfds);
if (select(server_socket + 1, &readfds, nullptr, nullptr, nullptr) < 0) {
perror("Помилка select");
break;
}
if (FD_ISSET(server_socket, &readfds)) {
int len = recvfrom(server_socket, buffer, DEFAULT_BUFLEN, 0,
(sockaddr*)&client_addr, &addrlen);
if (len < 0) {
perror("Помилка recvfrom");
continue;
}
buffer[len] = '\0';
string message = buffer;
cout << "Отримано від " << inet_ntoa(client_addr.sin_addr)
<< ":" << ntohs(client_addr.sin_port) << " → " << message << endl;
// Перевірка, чи клієнт вже є в списку
bool exists = false;
for (const auto& addr : clients) {
if (addr.sin_addr.s_addr == client_addr.sin_addr.s_addr &&
addr.sin_port == client_addr.sin_port) {
exists = true;
break;
}
}
if (!exists && clients.size() < MAX_CLIENTS) {
clients.push_back(client_addr);
cout << "Новий клієнт додано. Всього: " << clients.size() << endl;
// Надсилаємо історію новому клієнту
for (const auto& msg : history) {
sendto(server_socket, msg.c_str(), msg.size(), 0,
(sockaddr*)&client_addr, addrlen);
}
}
if (message == "off") {
cout << "Клієнт " << inet_ntoa(client_addr.sin_addr)
<< " відключився.\n";
for (auto it = clients.begin(); it != clients.end(); ++it) {
if (it->sin_addr.s_addr == client_addr.sin_addr.s_addr &&
it->sin_port == client_addr.sin_port) {
clients.erase(it);
break;
}
}
} else {
// Зберігаємо в історію
history.push_back(message);
// Розсилка всім іншим клієнтам
for (const auto& addr : clients) {
if (!(addr.sin_addr.s_addr == client_addr.sin_addr.s_addr &&
addr.sin_port == client_addr.sin_port)) {
sendto(server_socket, message.c_str(), len, 0,
(sockaddr*)&addr, sizeof(addr));
}
}
}
}
}
close(server_socket);
return 0;
}
=============================================================================================================================
CLIENT SIDE:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>
#include <thread>
#include <string>
#include <cstring>
#include <csignal>
#include <cstdio>
using namespace std;
#define DEFAULT_BUFLEN 4096
#define SERVER_IP "127.0.0.1"
#define PORT 8888
int client_socket;
sockaddr_in server_addr;
string nickname;
void sender() {
while (true) {
string query;
getline(cin, query);
if (query.empty()) continue;
string message = "[" + nickname + "]: " + query;
sendto(client_socket, message.c_str(), message.size(), 0,
(sockaddr*)&server_addr, sizeof(server_addr));
}
}
void receiver() {
char buffer[DEFAULT_BUFLEN];
sockaddr_in from_addr{};
socklen_t from_len = sizeof(from_addr);
while (true) {
int len = recvfrom(client_socket, buffer, DEFAULT_BUFLEN, 0,
(sockaddr*)&from_addr, &from_len);
if (len > 0) {
buffer[len] = '\0';
cout << buffer << endl;
} else if (len < 0) {
perror("Помилка recvfrom");
}
}
}
void signal_handler(int signum) {
cout << "\nВимкнення клієнта...\n";
sendto(client_socket, "off", 3, 0, (sockaddr*)&server_addr, sizeof(server_addr));
close(client_socket);
exit(0);
}
int main() {
signal(SIGINT, signal_handler); // Ctrl+C
signal(SIGTERM, signal_handler);
cout << "Введіть ваш нік: ";
getline(cin, nickname);
// Створення сокета
if ((client_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("Не вдалося створити сокет");
return 1;
}
// Прив'язка до будь-якого порту (локального)
sockaddr_in client_addr{};
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = INADDR_ANY;
client_addr.sin_port = 0;
if (bind(client_socket, (sockaddr*)&client_addr, sizeof(client_addr)) < 0) {
perror("Помилка bind");
close(client_socket);
return 2;
}
// Налаштування адреси сервера
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr);
// Реєстрація на сервері
string init_msg = "[" + nickname + "]: підключився";
sendto(client_socket, init_msg.c_str(), init_msg.size(), 0,
(sockaddr*)&server_addr, sizeof(server_addr));
cout << "Клієнт запущено. Нік: " << nickname << "\n";
thread send_thread(sender);
thread recv_thread(receiver);
send_thread.join();
recv_thread.join();
close(client_socket);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment