Надо мне приложение которое входящие данные выстраивает в очереди, сортирует итп. Решил реализовать при помощи файловых unix сокетов. Было бы удобно когда разные приложения кидают на сокет дейтаграммы, а он их там сортирует и обрабатывает в порядке очереди.
И тут я спросил у GPT:
Одно приложение отправляет на сокет строку 'aaaa'
Второе приложение отправляет строку 'bbbb'
Если они отправят эти строки одновременно, есть вероятность получить на сокете строку 'abab'?
На что он мне ответил:
Да, если два приложения отправляют строки "aaaa" и "bbbb" одновременно, то существует вероятность получить на сокете строку "abab" или другие комбинации букв из этих двух строк.
Это связано с тем, что сокеты работают на низком уровне и не гарантируют сохранение порядка отправленных данных. Когда два приложения отправляют данные одновременно, они могут перемешиваться в процессе передачи по сети и приходить в произвольном порядке.
Получается идея с сокетами не очень хороша? При параллельной отправке на сокет можно получить кашу?
Вот я тут небольшие тесты сделал, гонка данных не получается, сокет обрабатывает каждую дейтаграмму корректно, принимает их в порядке очереди без перемешивания.
Приложение отравляет многопоточно 5 дейтаграмм по 40 байт
#include <string>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <iostream>
#include <filesystem>
#include <thread>
#include <vector>
#define DATA_SIZE 40
int sock(const std::string &msg) {
// Создание файлового Unix сокета
int sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sockfd == -1)
{
std::cerr << "Ошибка при создании сокета" << std::endl;
return 1;
}
// Заполнение адреса сервера
const char *socketPath = "sock";
sockaddr_un serverAddr;
serverAddr.sun_family = AF_UNIX;
strncpy(serverAddr.sun_path, socketPath, sizeof(serverAddr.sun_path) - 1);
// Отправка дейтаграммы
auto message = msg.c_str();
ssize_t numBytes = sendto(sockfd, message, DATA_SIZE, 0, reinterpret_cast<sockaddr *>(&serverAddr), sizeof(serverAddr));
if (numBytes == -1)
{
std::cerr << "Ошибка при отправке дейтаграммы" << std::endl;
close(sockfd);
return 1;
}
// Закрытие сокета
close(sockfd);
return 0;
}
int main() {
const int numThreads = 5;
std::thread threads[numThreads];
std::vector<std::string> v{
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"cccccccccccccccccccccccccccccccccccccccc",
"dddddddddddddddddddddddddddddddddddddddd",
"ffffffffffffffffffffffffffffffffffffffff"
};
// Создание и запуск потоков
for (int i = 0; i < numThreads; ++i) {
threads[i] = std::thread(sock, v[i]);
}
// Ожидание завершения всех потоков
for (int i = 0; i < numThreads; ++i) {
threads[i].join();
}
std::cout << "All threads have finished" << std::endl;
return 0;
}
Приложение-получатель. Принимает и печатает дейтаграммы по 40 байт
#include <string>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <iostream>
#include <filesystem>
#include <thread>
#define DATA_SIZE 40
int main() {
// Создание файлового Unix сокета
int sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sockfd == -1)
{
std::cerr << "Ошибка при создании сокета" << std::endl;
return 1;
}
// Удаление существующего сокета с таким же именем
const char *socketPath = "sock";
unlink(socketPath);
// Связывание сокета с адресом
sockaddr_un address;
address.sun_family = AF_UNIX;
strncpy(address.sun_path, socketPath, sizeof(address.sun_path) - 1);
if (bind(sockfd, reinterpret_cast<sockaddr *>(&address), sizeof(address)) == -1)
{
std::cerr << "❌Socket::run: Error when binding a socket to an address." << std::endl;
close(sockfd);
return 1;
}
std::cout << "✅Socket::run: The socket was successfully created and associated with the address" << std::endl;
// Ожидание дейтаграммы
char buffer[DATA_SIZE];
sockaddr_un clientAddr;
socklen_t clientAddrLen = sizeof(clientAddr);
while (1)
{
ssize_t numBytes = recvfrom(sockfd, buffer, sizeof(buffer), 0, reinterpret_cast<sockaddr *>(&clientAddr), &clientAddrLen);
if (numBytes == -1)
{
std::cerr << "Socket::run: Error when receiving a datagram" << std::endl;
continue;
}
std::cout << buffer << std::endl;
// std::this_thread::sleep_for(std::chrono::seconds(1)); // пауза между приемами дейтаграмм.
}
// Закрытие сокета
close(sockfd);
return 0;
}
Вопрос: прав ли GPT? Действительно ли на сокете можно получить кашу из дейтаграмм?