Entendiendo htonl () y ntohl ()

Estoy intentando usar sockets Unix para probar el envío de algunos paquetes udp a localhost.

Tengo entendido que al configurar la dirección IP y el puerto para enviar paquetes, llenaría mi sockaddr_in con los valores convertidos en orden de byte de red. Estoy en OSX y me sorprende que esto

 printf("ntohl: %d\n", ntohl(4711)); printf("htonl: %d\n", htonl(4711)); printf("plain: %d\n", 4711); 

Huellas dactilares

 ntohl: 1729232896 htonl: 1729232896 plain: 4711 

Así que ninguna de las dos funciones devuelve el valor plano. Habría esperado ver que los resultados fueran diferentes, ya que x86 es little-endian (afaik), o ser idéntico y el mismo que el número real 4711. Claramente, no entiendo qué hacen htonl y ntohl y sus variantes. ¿Qué me estoy perdiendo?

El código relevante es este:

 int main(int argc, char *argv[]) { if (argc != 4) { fprintf(stderr, "%s\n", HELP); exit(-1); } in_addr_t rec_addr = inet_addr(argv[1]); // first arg is '127.0.0.1' in_port_t rec_port = atoi(argv[2]); // second arg is port number printf("Address is %s\nPort is %d\n", argv[1], rec_port); char* inpath = argv[3]; char* file_buf; unsigned long file_size = readFile(inpath, &file_buf); // I am trying to send a file if (file_size > 0) { struct sockaddr_in dest; dest.sin_family = AF_INET; dest.sin_addr.s_addr = rec_addr; // here I would use htons dest.sin_port = rec_port; printf("ntohs: %d\n", ntohl(4711)); printf("htons: %d\n", htonl(4711)); printf("plain: %d\n", 4711); int socket_fd = socket(AF_INET, SOCK_DGRAM, 0); if (socket_fd != -1) { int error; error = sendto(socket_fd, file_buf, file_size + 1, 0, (struct sockaddr*)&dest, sizeof(dest)); if (error == -1) fprintf(stderr, "%s\n", strerror(errno)); else printf("Sent %d bytes.\n", error); } } free(file_buf); return 0; } 

Ambas funciones invierten el orden de los bytes. ¿Por qué eso devolvería el argumento en sí?

Pruebe htons(ntohs(4711)) y ntohs(htons(4711)) .

Como han mencionado otros, tanto htons como ntohs invierten el orden de los bytes en una máquina little-endian, y no son operativos en las máquinas big-endian.

Lo que no se mencionó es que estas funciones toman un valor de 16 bits y devuelven un valor de 16 bits. Si desea convertir valores de 32 bits, desea usar htonl y ntohl en ntohl lugar.

Los nombres de estas funciones provienen de los tamaños tradicionales de ciertos tipos de datos. La s representa el short mientras que la l representa el long . Un short suele ser de 16 bits, mientras que en los sistemas más antiguos era de 32 bits.

En su código, no necesita llamar a htonl en rec_addr , porque htonl rec_addr ese valor, y esa función devuelve la dirección en orden de bytes de red.

Sin embargo, debe llamar a htons en rec_port .

“Orden de bytes de red” siempre significa big endian.

“Orden de bytes de host” depende de la architecture del host. Dependiendo de la CPU, el orden de bytes del host puede ser little endian, big endian o algo más. (g) libc se adapta a la architecture del host.

Debido a que la architecture de Intel es poco endian, esto significa que ambas funciones están haciendo lo mismo: revertir el orden de bytes.

estas funciones están mal nombradas. Host to network y la network to host son en realidad la misma cosa y deberían llamarse ‘cambiar endianness si esto es una pequeña máquina endian’

Así que en una máquina endian pequeña que haces

 net, ie be, number = htonl / ntohl (le number) 

y enviar el número de be en el cable. Y cuando obtienes un gran número endian del cable

 le num = htonl/ntohl (net ,ie be, number) 

en una máquina grande

 net, ie be, number = htonl / ntohl (be number) 

y

  be num = htonl/ntohl (net ,ie be, number) 

y en los últimos casos ves que estas funciones no hacen nada.