Ответ по UDP в C++
Ответ по UDP не опирается на отдельный список клиентов.
После recvfrom структура отправителя лежит
в sockaddr_in, которую передали в прием.
Ответ собирают из короткого текста на английском и
шлют тем же сокетом через sendto на этот
адрес. Запрос по-прежнему приходит из фонового
потока, чтобы приемник не ждал вечно.
Приемник прочитает запрос и вернет короткое подтверждение:
#include <arpa/inet.h>
#include <atomic>
#include <cstring>
#include <netinet/in.h>
#include <sys/socket.h>
#include <thread>
#include <unistd.h>
int main() {
std::atomic<bool> ready{false};
int recv_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (recv_fd == -1) {
return 1;
}
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 1;
}
ready.store(true, std::memory_order_release);
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";
sendto(
send_fd,
msg,
std::strlen(msg),
0,
reinterpret_cast<sockaddr*>(&dest),
sizeof(dest)
);
close(send_fd);
});
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[] = "ack";
sendto(
recv_fd,
reply,
std::strlen(reply),
0,
reinterpret_cast<sockaddr*>(&peer),
peer_len
);
}
close(recv_fd);
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[] = "got it";
sendto(
recv_fd,
reply,
std::strlen(reply),
0,
reinterpret_cast<sockaddr*>(&peer),
peer_len
);
}
close(recv_fd);
});
while (!ready.load(std::memory_order_acquire)) {
}
int send_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (send_fd == -1) {
receiver.join();
return 1;
}
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);
receiver.join();
return 1;
}
const char msg[] = "hello";
if (sendto(
send_fd,
msg,
std::strlen(msg),
0,
reinterpret_cast<sockaddr*>(&dest),
sizeof(dest)
) == -1) {
close(send_fd);
receiver.join();
return 1;
}
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();
return 0;
}
На запрос "check" ответьте текстом
"ok". Адрес отправителя возьмите из
принятого пакета.
На запрос "version" ответьте
"1.0" и выведите ответ на стороне
отправителя в консоль.