Привязка сокета к адресу компьютера для прослушивания

Я создал код, предназначенный для привязки нового сокета к адресам компьютера для прослушивания входящих соединений на определенном порту. Я использую getaddrinfo. Это лучший способ? Кажется бессмысленным преобразовывать целое число порта в строку. Есть ли способ сделать это без использования sprintf?

bool CBSocketBind(void * socketID,u_int16_t port){
    struct addrinfo hints,*res,*ptr;
    int socketIDInt;
    // Set hints for the computer's addresses.
    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_PASSIVE;
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    // Get host for listening
    char portStr[6];
    sprintf(portStr, "%u",port);
    if (getaddrinfo(NULL, portStr, &hints, &res) != 0)
        return false;
    // Attempt to bind to one of the addresses.
    for(ptr = res; ptr != NULL; ptr = ptr->ai_next) {
        if ((socketIDInt = socket(ptr->ai_family, ptr->ai_socktype,ptr->ai_protocol)) == -1)
            continue;
        if (bind(socketIDInt, ptr->ai_addr, ptr->ai_addrlen) == -1) {
            close(socketIDInt);
            continue;
        }
        break; // Success.
    }
    freeaddrinfo(res);
    if (ptr == NULL) // Failure
        return false;
    socketID = malloc(sizeof(int));
    *(int *)socketID = socketIDInt; // Set socket ID
    // Make socket non-blocking
    fcntl(socketIDInt,F_SETFL,fcntl(socketIDInt,F_GETFL,0) | O_NONBLOCK);
    return true;
}

person Matthew Mitchell    schedule 16.07.2012    source источник


Ответы (3)


Дизайн getaddrinfo() был предназначен для работы с любым сетевым протоколом, который может использовать другое обозначение для конкретной службы. Обозначение может не быть числовым или может использовать большее число, чем 16-битные целочисленные номера портов, используемые TCP. Для максимальной гибкости может быть предоставлено имя службы, которое может быть преобразовано в протокол, и любая другая информация, относящаяся к протоколу, например. ftp → TCP-порт IPv4 или IPv6 21. Если вы знаете, что всегда будете использовать IPv4 или IPv6 и TCP, вы можете передать NULL для имени службы и самостоятельно заполнить номер порта в возвращаемой структуре адреса сокета (поле sin_port для IPv4 или поле sin6_port для IPv6). Однако, вероятно, будет чище просто использовать sprintf(); это будет обрабатывать различные структуры адресов сокетов, используемые IPv4 и IPv6, и требование хранить номер порта в сетевом порядке байтов, а также может позволить вам поддерживать другие будущие протоколы без изменения кода.

person mark4o    schedule 16.07.2012

Причина, по которой getaddrinfo() принимает строку, а не целое число, заключается в том, что служба не обязательно должна быть просто портом. Пользователь может, например, запросить услугу «http».

person chrisaycock    schedule 16.07.2012
comment
Хорошо, спасибо. Если бы я разрабатывал getaddrinfo, я бы предоставил константы для распространенных протоколов, таких как http, вместо использования строк. Но если это идиоматический способ сделать это, то я просто должен оставить это так. Не большая проблема, конечно, мне просто не нравится, как это делается. Если у кого-то есть предложения по улучшению, я все равно посмотрю. - person Matthew Mitchell; 16.07.2012
comment
@MatthewMitchell Причина, по которой http не является константой, заключается в том, что администратор может добавлять новые службы, а также изменять порт по умолчанию для существующих служб. См. /etc/services на своем компьютере. - person chrisaycock; 16.07.2012
comment
Да, хотя имя порта может быть целым числом со знаком, где константы служб являются отрицательными числами, которые сопоставляются с номерами портов, используемыми системой. Но это не имеет значения. Так оно и есть. - person Matthew Mitchell; 16.07.2012
comment
Вы выступаете против чего-то, созданного в 70-х. Знали ли они тогда о http? :) - person JimR; 16.07.2012
comment
@MatthewMitchell Единственный способ сделать что-то вроде этого (1) портала, (2) перспективного и (3) универсального — не использовать предопределенные константы. Что, если MatthewMitchellProtocol (MMP) станет популярным в будущем? Любой, у кого в заголовочном файле не будет целочисленной константы MMP, будет облажался. Между тем, все, кто предусмотрительно просто использовал строковое представление, будут в порядке. - person chrisaycock; 17.07.2012
comment
Я просто сказал, что поступил бы так, но, конечно, сейчас бессмысленно пытаться что-то изменить. - person Matthew Mitchell; 17.07.2012

Это выглядит довольно идиоматично для того, как getaddrinfo() обычно используется в состоянии AI_PASSIVE. Типично строковое число.

person LeoNerd    schedule 16.07.2012
comment
ОК, спасибо, хотя, если есть лучший способ привязки сокета для прослушивания входящих соединений (по мнению всех), я готов прочитать предложения. - person Matthew Mitchell; 16.07.2012