Следите за новинками
в нашем Telegram канале. Жми, чтобы подписаться:)
⊗cpSpUdExc 685 of 696 menu
◀ ▶

Обмен UDP-сообщениями в C++

Полный цикл UDP в одной программе связывает два рабочих потока.

Поток-приемник сначала вызывает bind на 18081, читает запрос и шлет ответ. Поток-отправитель ждет сигнал о готовности, передает датаграмму на 127.0.0.1 и читает ответ на своем сокете. Оба потока завершают работу через join, каждый закрывает свой дескриптор.

Синхронизацию порта удобно делать через std::atomic<bool>: приемник поднимает флаг после привязки, затем отправитель работает. Ответ отправитель выведет строкой из байтов:

#include <arpa/inet.h> #include <atomic> #include <cstring> #include <iostream> #include <netinet/in.h> #include <string> #include <sys/socket.h> #include <thread> #include <unistd.h> int main() { std::atomic<bool> ready{false}; std::thread receiver([&]() { int recv_fd = socket(AF_INET, SOCK_DGRAM, 0); if (recv_fd == -1) { return; } sockaddr_in local{}; local.sin_family = AF_INET; local.sin_port = htons(18081); if (inet_pton(AF_INET, "127.0.0.1", &local.sin_addr) != 1 || bind( recv_fd, reinterpret_cast<sockaddr*>(&local), sizeof(local) ) == -1) { close(recv_fd); return; } ready.store(true, std::memory_order_release); char buf[256]; sockaddr_in peer{}; socklen_t peer_len = sizeof(peer); ssize_t n = recvfrom( recv_fd, buf, sizeof(buf), 0, reinterpret_cast<sockaddr*>(&peer), &peer_len ); if (n > 0) { const char reply[] = "pong"; sendto( recv_fd, reply, std::strlen(reply), 0, reinterpret_cast<sockaddr*>(&peer), peer_len ); } close(recv_fd); }); std::thread sender([&]() { while (!ready.load(std::memory_order_acquire)) { } int send_fd = socket(AF_INET, SOCK_DGRAM, 0); if (send_fd == -1) { return; } sockaddr_in dest{}; dest.sin_family = AF_INET; dest.sin_port = htons(18081); if (inet_pton(AF_INET, "127.0.0.1", &dest.sin_addr) != 1) { close(send_fd); return; } const char msg[] = "ping"; if (sendto( send_fd, msg, std::strlen(msg), 0, reinterpret_cast<sockaddr*>(&dest), sizeof(dest) ) == -1) { close(send_fd); return; } char ans_buf[256]; sockaddr_in from{}; socklen_t from_len = sizeof(from); ssize_t ans_n = recvfrom( send_fd, ans_buf, sizeof(ans_buf), 0, reinterpret_cast<sockaddr*>(&from), &from_len ); if (ans_n > 0) { std::string answer(ans_buf, static_cast<size_t>(ans_n)); std::cout << answer << "\n"; } close(send_fd); }); receiver.join(); sender.join(); return 0; }

Тот же каркас подходит для других коротких фраз. Главное - не закрывать сокет отправителя до приема ответа и держать приемник в потоке, пока идет обмен:

#include <arpa/inet.h> #include <atomic> #include <cstring> #include <iostream> #include <netinet/in.h> #include <string> #include <sys/socket.h> #include <thread> #include <unistd.h> int main() { std::atomic<bool> ready{false}; std::thread receiver([&]() { int recv_fd = socket(AF_INET, SOCK_DGRAM, 0); if (recv_fd == -1) { return; } sockaddr_in local{}; local.sin_family = AF_INET; local.sin_port = htons(18081); if (inet_pton(AF_INET, "127.0.0.1", &local.sin_addr) != 1 || bind( recv_fd, reinterpret_cast<sockaddr*>(&local), sizeof(local) ) == -1) { close(recv_fd); return; } ready.store(true, std::memory_order_release); char buf[256]; sockaddr_in peer{}; socklen_t peer_len = sizeof(peer); ssize_t n = recvfrom( recv_fd, buf, sizeof(buf), 0, reinterpret_cast<sockaddr*>(&peer), &peer_len ); if (n > 0) { const char reply[] = "done"; sendto( recv_fd, reply, std::strlen(reply), 0, reinterpret_cast<sockaddr*>(&peer), peer_len ); } close(recv_fd); }); std::thread sender([&]() { while (!ready.load(std::memory_order_acquire)) { } int send_fd = socket(AF_INET, SOCK_DGRAM, 0); if (send_fd == -1) { return; } sockaddr_in dest{}; dest.sin_family = AF_INET; dest.sin_port = htons(18081); if (inet_pton(AF_INET, "127.0.0.1", &dest.sin_addr) != 1) { close(send_fd); return; } const char msg[] = "start job"; if (sendto( send_fd, msg, std::strlen(msg), 0, reinterpret_cast<sockaddr*>(&dest), sizeof(dest) ) == -1) { close(send_fd); return; } char ans_buf[256]; sockaddr_in from{}; socklen_t from_len = sizeof(from); ssize_t ans_n = recvfrom( send_fd, ans_buf, sizeof(ans_buf), 0, reinterpret_cast<sockaddr*>(&from), &from_len ); if (ans_n > 0) { std::string answer(ans_buf, static_cast<size_t>(ans_n)); std::cout << answer << "\n"; } close(send_fd); }); receiver.join(); sender.join(); return 0; }

Отправьте "time" и выведите ответ "now" в консоли отправителя.

Обменяйтесь фразами "ask" и "reply" в одном запуске. На экране должна появиться только строка ответа.

← →
↑
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить