Вопрос

I've created code designed to bind a new socket to the computer's addresses for listening for incoming connections on a specific port. I'm using getaddrinfo. Is this the best way? It seems pointless converting the port integer to a string. Is there a way to do this with no need for 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;
}
Это было полезно?

Решение

The design of getaddrinfo() was intended to accommodate any network protocol, which may use a different designation for a particular service. The designation may not be numeric, or may use a larger number than the 16-bit integer port numbers used by TCP. For maximal flexibility a service name may be provided, which can be translated to a protocol and any other information specific to the protocol, e.g. ftp → IPv4 or IPv6 TCP port 21. If you know that you will always be using IPv4 or IPv6 and TCP then you can pass NULL for the service name and fill in the port number yourself in the returned socket address structure (sin_port field for IPv4 or sin6_port field for IPv6). However, it is probably cleaner to just use sprintf(); this will handle the different socket address structures used by IPv4 and IPv6, and the requirement to store the port number in network byte order, and may also allow you to support other future protocols without code changes.

Другие советы

The reason getaddrinfo() takes a string rather than an integer is that the service doesn't have to be just a port. The user could, for example, ask for service "http".

That looks fairly idiomatic of how getaddrinfo() is normally used in AI_PASSIVE state. The stringified number is typical.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top