J'essaie d'utiliser des sockets unix pour tester l'envoi de paquets udp à localhost.
Je crois comprendre que lors de la configuration de l'adresse IP et du port afin d'envoyer des paquets, je remplissais mon sockaddr_in
avec les valeurs converties en ordre d'octets réseau . Je suis sur OSX et je suis étonné de ce
printf("ntohl: %d\n", ntohl(4711));
printf("htonl: %d\n", htonl(4711));
printf("plain: %d\n", 4711);
Impressions
ntohl: 1729232896
htonl: 1729232896
plain: 4711
Donc, ni l'une ni l'autre des fonctions ne renvoie réellement la valeur simple. Je me serais attendu à ce que les résultats diffèrent, car x86 est un petit bout (afaik), ou identiques et identiques au nombre 4711. De toute évidence, je ne comprends pas ce que htonl
et ntohl
et leurs variantes font. Qu'est-ce que je rate?
Le code pertinent est le suivant:
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;
}
Les deux fonctions inversent l'ordre des octets. Pourquoi cela renverrait l'argument lui-même?
Essayez htons(ntohs(4711))
et ntohs(htons(4711))
.
Comme d'autres l'ont mentionné, htons
et ntohs
inversent l'ordre des octets sur une machine little-endian et ne fonctionnent pas sur les machines big-endian.
Ce qui n'a pas été mentionné, c'est que ces fonctions prennent une valeur de 16 bits et retournent une valeur de 16 bits. Si vous souhaitez convertir des valeurs 32 bits, vous souhaitez plutôt utiliser htonl
et ntohl
.
Les noms de ces fonctions proviennent des tailles traditionnelles de certains types de données. s
représente short
tandis que l
correspond à long
. short
est généralement 16 bits alors que sur les systèmes plus anciens long
était 32 bits.
Dans votre code, vous n'avez pas besoin d'appeler htonl
sur rec_addr
, car cette valeur a été renvoyée par inet_addr
et cette fonction renvoie l'adresse dans l'ordre des octets du réseau.
Vous devez toutefois appeler htons
sur rec_port
.
"Ordre des octets du réseau" signifie toujours big endian.
"L'ordre des octets de l'hôte" dépend de l'architecture de l'hôte. Selon le processeur, l’ordre des octets de l’hôte peut être petit, grand ou autre. (g) la libc s'adapte à l'architecture de l'hôte.
L’architecture d’Intel étant peu évolutive, cela signifie que les deux fonctions agissent de la même manière: inverser l’ordre des octets.
ces fonctions sont mal nommées. Host to network
et network to Host
sont en réalité la même chose et devraient être appelés 'changer d'endianisme s'il s'agit d'une petite machine endian'
Donc, sur une petite machine endian vous faites
net, ie be, number = htonl / ntohl (le number)
et envoyez le numéro sur le fil. Et quand vous obtenez un grand nombre final du fil
le num = htonl/ntohl (net ,ie be, number)
sur une grosse machine
net, ie be, number = htonl / ntohl (be number)
et
be num = htonl/ntohl (net ,ie be, number)
et dans les derniers cas, vous voyez que ces fonctions ne font rien