Created
March 27, 2026 09:04
-
-
Save sunmeat/c2c2f4cf7e5b11b8f728462dcdcbb4ca to your computer and use it in GitHub Desktop.
one server multiple clients C++ example (UDP) mac os 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
| 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