Прием UDP-пакета в C++
Приемник UDP держит буфер фиксированного размера и ждет первый пакет.
Вызов recvfrom заполняет буфер и возвращает
число прочитанных байтов. Строку собирают только по
этой длине, а не по всему массиву. Чтобы ожидание
не длилось бесконечно без данных, отправку запускают
в отдельном std::thread после успешного
bind.
Приемник на 18081 выведет текст, а поток
отправит короткое сообщение на 127.0.0.1:
#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};
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[] = "note";
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) {
std::string text(buf, static_cast<size_t>(n));
std::cout << text << "\n";
}
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};
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[] = "status ok";
sendto(
send_fd,
msg,
std::strlen(msg),
0,
reinterpret_cast<sockaddr*>(&dest),
sizeof(dest)
);
close(send_fd);
});
char buf[512];
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) {
std::string text(buf, static_cast<size_t>(n));
std::cout << text.size() << "\n";
}
close(recv_fd);
sender.join();
return 0;
}
Примите один пакет с текстом "ready" и
выведите его в консоль одной строкой.
После приема текста "metric" выведите
число символов в полученной строке.