You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

5.4 KiB

socket_compat — Cross-platform socket abstraction

1. Назначение

Унифицирует работу с UDP-сокетами между POSIX и Windows (MSYS2 UCRT64). Скрывает различия в типах дескрипторов (int vs SOCKET), инициализации подсистемы (WSAStartup/WSACleanup), кодах ошибок и сигнатурах системных вызовов.

2. Как пользоваться

Инициализация (однократно при старте)

if (socket_platform_init() != 0) { /* фатальная ошибка */ }
// ... работа с сокетами ...
socket_platform_cleanup();   // при завершении

На Windows WSAStartup/WSACleanup с refcount — можно вызывать init/cleanup вложенно.

Создание и настройка сокета

socket_t sock = socket_create_udp(AF_INET);     // или AF_INET6
if (sock == SOCKET_INVALID) { /* ошибка */ }

socket_set_nonblocking(sock);                   // обязательно для u_async
socket_set_reuseaddr(sock, 1);
socket_set_buffers(sock, 256*1024, 256*1024);   // SO_SNDBUF/SO_RCVBUF
socket_bind_to_device(sock, "eth0");            // только Linux, SO_BINDTODEVICE
socket_set_mark(sock, 42);                      // только Linux, SO_MARK

Отправка и приём

ssize_t sent = socket_sendto(sock, buf, len, (struct sockaddr*)&addr, addr_len);
ssize_t recv = socket_recvfrom(sock, buf, sizeof(buf), (struct sockaddr*)&src, &src_len);

uint16_t port = ss_get_port(&src);              // порт из sockaddr_storage

Обработка ошибок

if (sent == SOCKET_ERROR_CODE) {
    int err = socket_get_error();
    if (err == ERR_WOULDBLOCK) { /* нормально для неблокирующего */ }
    // на POSIX ERR_WOULDBLOCK == EWOULDBLOCK (может совпадать с EAGAIN)
    DEBUG_ERROR(..., "%s", socket_strerror(err));
}

Закрытие

socket_close_wrapper(sock);   // на POSIX: close() с защитой от fd 0

Ключевые нюансы

  • Всегда вызывать socket_platform_init() перед работой — иначе на Windows сокеты не будут работать
  • Всегда socket_set_nonblocking() — u_async требует неблокирующих сокетов
  • socket_t — на POSIX int, на Windows SOCKET (unsigned)
  • SOCKET_INVALID — константа для невалидного сокета (-1 на POSIX, INVALID_SOCKET на Windows)
  • SOCKET_ERROR_CODE — код ошибки сокетных вызовов (-1 на POSIX, SOCKET_ERROR на Windows)
  • socket_strerror() на Windows использует статический буфер — не thread-safe для параллельного использования
  • socket_bind_to_device и socket_set_mark — только Linux, на остальных платформах возвращают -1 с DEBUG-сообщением
  • socket_close_wrapper на POSIX не закроет fd 0 (защита)

3. API

Типы и константы

Имя Назначение
socket_t Кроссплатформенный тип дескриптора сокета (int / SOCKET)
SOCKET_INVALID Невалидный сокет (-1 / INVALID_SOCKET)
SOCKET_ERROR_CODE Код ошибки сокетного вызова (-1 / SOCKET_ERROR)
ERR_WOULDBLOCK / ERR_AGAIN / ERR_INTR Кроссплатформенные коды ошибок

Инициализация

Функция Назначение
socket_platform_init() Инициализация сокетной подсистемы (WSAStartup на Windows). 0 — успех
socket_platform_cleanup() Деинициализация (WSACleanup на Windows), refcount

Создание и настройка

Функция Назначение
socket_create_udp(family) Создать UDP-сокет (AF_INET или AF_INET6)
socket_set_nonblocking(sock) Перевести в неблокирующий режим
socket_set_buffers(sock, snd, rcv) Установить SO_SNDBUF и SO_RCVBUF
socket_set_reuseaddr(sock, reuse) Установить SO_REUSEADDR
socket_bind_to_device(sock, ifname) Привязать к интерфейсу (Linux SO_BINDTODEVICE)
socket_set_mark(sock, mark) Установить SO_MARK (Linux)

I/O

Функция Назначение
socket_sendto(sock, buf, len, dest, dest_len) Отправить UDP-датаграмму
socket_recvfrom(sock, buf, len, src, src_len) Принять UDP-датаграмму

Утилиты

Функция Назначение
socket_get_error() Текущий код ошибки (inline: WSAGetLastError() / errno)
socket_strerror(err) Текстовое описание ошибки (Windows: статический буфер, не thread-safe)
socket_close_wrapper(sock) Закрыть сокет (POSIX: защита от закрытия fd 0)
ss_get_port(addr) Извлечь порт в host byte order из sockaddr_storage