Aller au menu - Aller au contenu

Icône La transmission de flux

Avatar
Mise à jour : 05/05/2009
Difficulté : Intermédiaire Intermédiaire
3 369 visites depuis 7 jours, dont 300 sur ce chapitre classé 48/786
Dans ce chapitre, nous allons apprendre à transmettre des flux d'octets du serveur au client.
Vous verrez que ce que l'on va apprendre est le coeur d'une communication entre le Client et le Serveur. Pour cela, nous allons devoir découvrir d'autres fonctions :p .
Sommaire du chapitre :
Icône du chapitre
Chapitre précédent Sommaire Chapitre suivant

Transmission d'une chaîne de caractères

Pour pouvoir réaliser une transmission de données, le programme serveur va devoir envoyer des données, et le programme client les recevoir.

Pour cela, nous allons utiliser trois fonctions :
  • La fonction send, qui va envoyer les données (sous forme de tableau de char).
  • La fonction recv, qui va recevoir ce qu'a envoyé la fonction send (sous forme de tableau de char).
  • La fonction shutdown, qui va désactiver les envois et les réceptions sur la socket.
Premièrement, nous allons revenir sur le code source du programme serveur, pour étudier le fonctionnement de la fonction send.


La fonction send



Voici son prototype :

Code : C
1
int send(int socket, void* buffer, size_t len, int flags);
  • La fonction retourne SOCKET_ERROR en cas d'erreur, sinon elle retourne le nombre d'octets envoyés.
  • Le premier paramètre représente la socket destinée à recevoir le message.
  • Le deuxième représente un pointeur (comme par exemple un tableau) dans lequel figureront nos informations à transmettre.
  • Le paramètre len indique le nombre d'octets à lire.
  • Le dernier correspond au type d'envoi ; il nous est inutile, nous le mettrons donc à 0 pour avoir un envoi normal.
La fonction est très simple :

Code : C
1
send(sock, buffer, sizeof(buffer), 0);


sizeof(buffer) n'est pas toujours la bonne valeur à mettre pour le troisième paramètre. Par exemple, pour les chaînes de caractères, on peut utiliser la fonction strlen pour connaitre la taille de la chaine (en lui ajoutant 1 pour le caractère '\0'). De même, pour un tableau, il faut passer en paramètre la taille totale du que prend le tableau (nombre de cases * taille d'une case).


La fonction recv



Maintenant, nous allons nous pencher sur l'application client. Pour pouvoir étudier maintenant la fonction recv.
Cette fonction est aussi simple que la fonction send, et son fonctionnement le même :

Code : C
1
int recv(int socket, void* buffer, size_t len, int flags)
  • La fonction retourne SOCKET_ERROR en cas d'erreur, sinon elle retourne le nombre d'octets lus.
  • Le premier paramètre représente la socket destinée à attendre un message.
  • Le deuxième représente un pointeur (un tableau, par exemple) dans lequel résideront les informations à recevoir.
  • Le paramètre len indique le nombre d'octets à lire.
  • De même, le dernier correspond au type d'envoi : il nous est également inutile, nous le mettrons donc aussi à 0.
Nous recevrons les données envoyées comme cela par exemple :

Code : C
1
recv(sock, buffer, sizeof(buffer), 0);


Tout comme la fonction send, sizeof(buffer) n'est pas toujours la bonne taille à mettre pour le troisième paramètre. Pour cette fonction il ne faut pas mettre une valeur plus grande que la taille du tableau elle-même. Sinon, on risque de voir le programme boguer :p . Par exemple, pour les chaînes de caractères nous devrions envoyer d'abord un entier qui spécifie la taille de la chaine puis envoyer la chaine elle-même (sans le caractère '\0'). Une autre méthode consiste à lire les octets de la chaine un à un jusqu'à se que le caractère '\0' soit trouvé mais cette méthode est moins performante que la précédente bien qu'elle réduise la taille des données envoyées ;) .


La fonction shutdown



Voici le prototype de la dernière fonction : elle servira à fermer la transmission de données entre le serveur et le client.

Code : C
1
int shutdown(int socket, int how);
  • la fonction retourne la valeur -1 en cas d'erreur, sinon elle retourne la valeur 0.
  • Le premier paramètre désigne sur quel socket on doit fermer la connection.
  • Le deuxième paramètre définit où va se fermer la transition. Il peut prendre trois valeurs : 0, pour fermer la socket en réception, 1, en émission, 2 dans les deux sens.
Nous l'utiliserons ainsi, si l'on se place du côté du serveur :

Code : C
1
shutdown(sock, 2);


Maintenant que nous avons tout, nous allons faire le point et améliorer nos deux applications.


Faisons le point



Nous allons améliorer nos deux applications pour qu'elles se transmettent des données : pour cela, nous allons nous servir des trois fonctions précédemment apprises...

Nous allons du côté serveur envoyer un "bonjour" quand un client se connecte, puis fermer l'application.
Du côté client, nous allons recevoir la chaîne de caractères, et l'afficher à l'écran.

Vous pouvez vous lancer maintenant, ce n'est pas difficile ;) . Je suis même persuadé que vous pouvez le faire :p .

Codons ... ...
... ... ... ...

C'est fini ! Voilà la correction ^^ :

Secret (cliquez pour afficher)

L'application SERVEUR :



Code : C
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
#if defined (WIN32)
    #include <winsock2.h>
    typedef int socklen_t;
#elif defined (linux)
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #define INVALID_SOCKET -1
    #define SOCKET_ERROR -1
    #define closesocket(s) close(s)
    typedef int SOCKET;
    typedef struct sockaddr_in SOCKADDR_IN;
    typedef struct sockaddr SOCKADDR;
#endif
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PORT 23
 
 
 
int main(void)
{
    #if defined (WIN32)
        WSADATA WSAData;
        int erreur = WSAStartup(MAKEWORD(2,2), &WSAData);
    #else
        int erreur = 0;
    #endif
 
    SOCKET sock;
    SOCKADDR_IN sin;
    SOCKET csock;
    SOCKADDR_IN csin;
    char buffer[32] = "Bonjour !";
    socklen_t recsize = sizeof(csin);
    int sock_err;
 
    /* Si les sockets Windows fonctionnent */
    if(!erreur)
    {
        sock = socket(AF_INET, SOCK_STREAM, 0);
 
        /* Si la socket est valide */
        if(sock != INVALID_SOCKET)
        {
            printf("La socket %d est maintenant ouverte en mode TCP/IP\n", sock);
 
            /* Configuration */
            sin.sin_addr.s_addr    = htonl(INADDR_ANY);   /* Adresse IP automatique */
            sin.sin_family         = AF_INET;             /* Protocole familial (IP) */
            sin.sin_port           = htons(PORT);         /* Listage du port */
            sock_err = bind(sock, (SOCKADDR*)&sin, sizeof(sin));
 
            /* Si la socket fonctionne */
            if(sock_err != SOCKET_ERROR)
            {
                /* Démarrage du listage (mode server) */
                sock_err = listen(sock, 5);
                printf("Listage du port %d...\n", PORT);
 
                /* Si la socket fonctionne */
                if(sock_err != SOCKET_ERROR)
                {
                    /* Attente pendant laquelle le client se connecte */
                    printf("Patientez pendant que le client se connecte sur le port %d...\n", PORT);        
 
                    csock = accept(sock, (SOCKADDR*)&csin, &recsize);
                    printf("Un client se connecte avec la socket %d de %s:%d\n", csock, inet_ntoa(csin.sin_addr), htons(csin.sin_port));
 
                    sock_err = send(csock, buffer, 32, 0);
 
                    if(sock_err != SOCKET_ERROR)
                        printf("Chaine envoyée : %s\n", buffer);
                    else
                        printf("Erreur de transmission\n");
 
                    /* Il ne faut pas oublier de fermer la connexion (fermée dans les deux sens) */
                    shutdown(csock, 2);
                }
            }
 
            /* Fermeture de la socket */
            printf("Fermeture de la socket...\n");
            closesocket(sock);
            printf("Fermeture du serveur terminee\n");
        }
 
        #if defined (WIN32)
            WSACleanup();
        #endif
    }
 
    /* On attend que l'utilisateur tape sur une touche, puis on ferme */
    getchar();
 
    return EXIT_SUCCESS;
}


L'application CLIENT



Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#if defined (WIN32)
    #include <winsock2.h>
    typedef int socklen_t;
#elif defined (linux)
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #define INVALID_SOCKET -1
    #define SOCKET_ERROR -1
    #define closesocket(s) close(s)
    typedef int SOCKET;
    typedef struct sockaddr_in SOCKADDR_IN;
    typedef struct sockaddr SOCKADDR;
#endif
 
#include <stdio.h>
#include <stdlib.h>
#define PORT 23
 
 
 
int main(void)
{
    #if defined (WIN32)
        WSADATA WSAData;
        int erreur = WSAStartup(MAKEWORD(2,2), &WSAData);
    #else
        int erreur = 0;
    #endif
 
    SOCKET sock;
    SOCKADDR_IN sin;
    char buffer[32] = "";
 
    /* Si les sockets Windows fonctionnent */
    if(!erreur)
    {
        /* Création de la socket */
        sock = socket(AF_INET, SOCK_STREAM, 0);
 
        /* Configuration de la connexion */
        sin.sin_addr.s_addr = inet_addr("127.0.0.1");
        sin.sin_family = AF_INET;
        sin.sin_port = htons(PORT);
 
        /* Si l'on a réussi à se connecter */
        if(connect(sock, (SOCKADDR*)&sin, sizeof(sin)) != SOCKET_ERROR)
        {
            printf("Connection à %s sur le port %d\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port));
            
            /* Si l'on reçoit des informations : on les affiche à l'écran */
            if(recv(sock, buffer, 32, 0) != SOCKET_ERROR)
                printf("Recu : %s\n", buffer);
        }
        /* sinon, on affiche "Impossible de se connecter" */
        else
        {
            printf("Impossible de se connecter\n");
        }
 
        /* On ferme la socket */
        closesocket(sock);
 
        #if defined (WIN32)
            WSACleanup();
        #endif
    }
 
    /* On attend que l'utilisateur tape sur une touche, puis on ferme */
    getchar();
 
    return EXIT_SUCCESS;
}


Au lieu d'envoyer 32 octets de chaine de caractères (dans le cas ou sizeof(char)=1) nous aurions pu n'envoyer que 10 octets (c'est la taille de la chaine "Bonjour !"). Mais le problème qui se serait posé est que l'application client ne connait pas la taille de la chaine envoyée par le serveur. Il y a plusieurs solution pour régler ce problème comme envoyer un nombre qui précède la chaine spécifiant sa taille ou de lire la chaine de caractère reçu bits à bits jusqu'à se que l'on trouve le caractère '\0'. Ici, pour faire simple, nous n'allons pas déployer ces principes.


Sachez que vous pouvez créer un fichier header.h qui contient les inclusions, typedef et déclarations. Je ne l'ai pas fait pour éviter de vous perdre, avec les fichiers (déjà pas facile, les sockets... avec deux applications :p ). C'est en temps normal vivement recommandé ^^ .

Transmission d'une structure


La transmission de structures, d'entiers (de type int, short, long...), de nombres décimaux (double, float...), etc. Bref, tout ce qui n'est pas une chaine de caractères ne fonctionne qu'en local. La transmission d'autres choses que des chaines de caractères est expliquée à la fin de ce chapitre.


Comme nous l'avons vu, les fonctions send et recv permettent la transmission de nombres et de tableaux (dont les chaînes de caractères). Mais cela ne s'arrête pas là. Ces deux fonctions permettent aussi l'envoi de structures et même plus :D ! Il suffira juste de donner un pointeur de la structure aux deux fonctions et la taille que prend cette structure en mémoire ^^ . Bien sûr, il faudra que les déclarations des structures soient présentes dans les deux projets ;) .

Prenons par exemple une structure Point contenant deux entiers correspondants aux coordonnées X et Y du point. Eh bien au lieu de passer les données par un tableau il vous suffira de passer l'adresse de cette structure (à l'aide du symbole '&'). Dans cet exemple, il n'est pas plus difficile de passer les variables X et Y dans un tableau de 2 cases, mais dans le cas d'une grosse structure cela peux vraiment vous aider. Prenons maintenant une structure déclarée comme ci-dessous :

Code : C
1
2
3
4
5
6
struct Joueur
{
    int ID;
    char nom[256];
    char prenom[256];
};

Eh bien dans ce cas, l'envoi d'un tableau peut paraître délicat alors qu'en envoyant une structure vous pourrez accéder facilement aux données qu'elle comporte.

Passons donc maintenant à la pratique :) .
Nous allons créer une structure Personnage qui contiendra le nom, le prénom et l'âge de celui-ci :

Code : C
1
2
3
4
5
6
7
struct Personnage
{
    char nom[256];
    char prenom[256];
    int age;
};
typedef struct Personnage Personnage;

Rien de bien compliqué ^^ .
Comme dit plus haut, ce code devra être écrit dans les deux projets.
Ensuite nous allons déclarer une variable de type Personnage et remplir ses composantes :

Code : C
1
2
3
4
5
Personnage monPersonnage;
[...]
sprintf(monPersonnage.nom, "Matin");
sprintf(monPersonnage.prenom, "Dupont");
monPersonnage.age = 29;

Mon personnage se nommera donc Matin Dupont et aura 29 ans :p .

Maintenant, nous allons envoyer cette structure à un client en tant que serveur:

Code : C
1
send(sock, &monPersonnage, sizeof(monPersonnage), 0);

Et le client va recevoir cette structure avec la fonction recv :

Code : C
1
recv(sock, &monPersonnage, sizeof(monPersonnage), 0)

Du côté du client, la structure devra être déclarée. Elle sera automatiquement remplacée par la structure reçue.


Et maintenant ... Comment peut-on accéder à la structure reçue du côté du client ?

Eh bien tous simplement comme n'importe quelle structure ^^ . Faîtes un petit printf avec comme paramètre monPersonnage.age, vous verrez que la console vous affichera 29 (à part si vous avez mis autre chose :p ). Il en est de même pour les deux autres paramètres.

Vous l'avez peu être compris, vous pouvez transmettre tous les types de données que vous voulez (int, char, long, structures, etc.) avec les fonctions send et recv à condition que ce type soit déclaré dans le code serveur et aussi dans le code client.

Vous remarquerez que les deux chaînes de caractères qui étaient contenues dans nos structures disposaient d'une taille fixe (256 caractères avec le caractère '\0' inclus). Si nous voulons ne pas avoir cette limitation, il faut utiliser des pointeurs à la place et les allouer dynamiquement. Mais cela pose un problème car en envoyant la structure contenant les pointeurs on ne fait qu'envoyer la valeur des pointeurs (là ou il pointe) mais pas les variables sur lesquels ils pointent. Il faut donc envoyer aussi les données pointées par ces pointeurs ;) .

Un problème de portabilité

Jusque là, nous avons transmis des données d'un ordinateur à un autre sans faire attention aux types de données que nous transmettions. Mais cela pose de sérieux problèmes de portabilité.
En effet, après avoir sûrement lu le cours de M@téo21 sur l'allocation dynamique vous avez appris que, par exemple, la taille d'une variable de type int peut varier d'un ordinateur à un autre.
Donc, si nous envoyons une variable de type int à partir d'un ordinateur où le type int fait 8 octets sur un autre ordinateur où le type int fait 2 octets cela posera irrémédiablement problème : Pendant que l'ordinateur source envoi une seule variable de type int codée sur 8 octets, l'ordinateur de destination se verra recevoir 4 variables de type int :-° !
Ce problème pourrait être réglé en utilisant un type de données qui garde le même nombre d'octets d'un ordinateur à autre...
Mais voilà qu'il y à un second problème : l'ordre des octets d'une variable codée sur plusieurs octets n'est pas toujours le même non plus :( .
Il y a plusieurs façon de représenter un groupe d'octets en mémoire, on peut commencer par l'octet de poids fort ou par l'octet de poids faible par exemple, cela s'appelle l'Endianness (ou boutisme en français). Si un groupe d'octet commence par l'octet de poids fort on dit que sont orientation est big-endian, s'il commence par l'octet de poids faible on dit que sont orientation est little-endian. La façon d'organiser un groupe d'octet en mémoire dépend de l'architecture de la machine.


Pour résumer...



Si votre application communique avec une autre application qui se trouve sur le même ordinateur, il n'y aura donc pas de problème car la taille des types de données ne change pas d'une application à une autre, de même pour l'ordre des octets d'une variable en mémoire.
A contrario, pour réaliser une communication portable entre deux ordinateurs, il faut absolument transmettre les octets de nos variables un à un selon un ordre donné qui est le même pour les deux applications distantes. Des fonctions existent pour réaliser ces manipulations, nous allons donc commencer par les étudier puis nous allons les utiliser dans le cadre d'un exemple pour bien comprendre leur fonctionnement.


Fonctions de conversion



Deux groupes de fonctions de conversion de l'ordre des octets existe. Le premier groupe de fonctions a pour but de convertir un entier qui à l'endianness de votre ordinateur en un entier qui à l'endianness du réseau qui est toujours en big-endian (octet de poids fort en première position). Le second groupe de fonctions a pour but de faire la même opération mais dans le sens opposé.


Code : C
1
2
3
4
5
6
7
unsigned long htonl(unsigned long hostlong);

unsigned short htons(unsigned short hostshort);

unsigned long ntohl(unsigned long netlong);

unsigned short ntohs(unsigned short netshort);


La fonction htonl convertit l'entier de 4 octets hostlong depuis l'ordre des octets de l'hôte vers celui du réseau.
La fonction htons convertit l'entier de 2 octets hostshort depuis l'ordre des octets de l'hôte vers celui du réseau.

La fonction ntohl convertit l'entier de 4 octets netlong depuis l'ordre des octets du réseau vers celui de l'hôte.
La fonction ntohs convertit l'entier de 2 octets net­short depuis l'ordre des octets du réseau vers celui de l'hôte.


Un exemple de fonctionnement des fonctions htonl et ntohl



Supposons que vous vouliez transmettre un entier codée sur 4 octets à un autre ordinateur de manière portable. Il va falloir décomposer l'entier en 4 parties et envoyer chaque octet un à un.
De même pour la réception sauf qu'il va juste falloir faire l'opération inverse.

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void send4(int sock, unsigned long data)
{
    // Tableau d'octet qui sera ensuite envoyé
    char dataSend[4];
    
    // On décompose l'entier 'data' de 4 octets en 4 parties de 1 octet
    dataSend[0] = (data >> 24) & 0xFF;  // On sélectionne l'octet de poids fort de 'data' que l'on met dans la première case du tableau d'octet 'dataSend'
    dataSend[1] = (data >> 16) & 0xFF;  // De même avec l'octet qui suit
    dataSend[2] = (data >> 8) & 0xFF;   // De même avec l'octet qui suit
    dataSend[3] = (data >> 0) & 0xFF;   // On sélectionne l'octet de poids faible de 'data' que l'on met dans la dernière case du tableau d'octet 'dataSend'

    // On envoi les 4 octets dans un ordre qui ne change jamais quelque soit la machine
    send(sock, dataSend, 4, 0);
}

void read4(int sock, unsigned long* data)
{
    char dataRecv[4];
    
    // On reçoit une suite de 4 octets, le premier octet reçu est toujours l'octet de poids fort
    recv(sock, dataRecv, 4, 0);
    
    // On rassemble les 4 octets séparé en une seul variable de 4 octets
    unsigned long temp = 0;
    temp |= dataRecv[0] << 24;
    temp |= dataRecv[1] << 16;
    temp |= dataRecv[2] << 8;
    temp |= dataRecv[3] << 0;
    
    // On fini par copier le résultat dans 'data'
    *data = temp;
}


Ces deux fonctions sont un peu lourdes donc je vous conseil d'utiliser plutôt les fonctions de conversion spécifiées plus haut. Voici les même fonctions send4 et read4 implémentées en utilisant les fonctions htonl et ntohl :

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
void send4(int sock, unsigned long data)
{
    // On convertit data en entier big-endian
    long dataSend = htonl(data);
    
    // On envoie l'entier convertit
    send(sock, (char*)&dataSend, 4, 0);
}

void read4(int sock, unsigned long* data)
{
    long dataRecv;
    
    // On récupère l'entier en big-endian
    recv(sock, (char*)&dataRecv, 4, 0);
    
    // On convertit l'entier récupéré en little-endian si l'ordinateur 
    // stock les entiers en mémoire en little-endian, sinon s'il les 
    // stock en big-endian l'entier est convertit en big-endian
    *data = ntohl(dataRecv);
}


Notez que si vous voulez envoyer un entier de 2 octets le fonctionnement est exactement le même :) .
Pour ce qui est de la transmission de structures, il faudra envoyer chaque éléments qui la compose un à un pour que le code reste portable.

Q.C.M.

Je dispose d'un tableau 'couleur' déclaré et initialisé comme il suit :

Code : C
1
2
3
float couleur[3] = {0.7f, 0.1f, 0.9f};
...
send(csock, couleur, sizeof(float) * 3, 0);

Ai-je le droit de transmettre cette structure directement du serveur au client sachant que je sais que l'application serveur et l'application cliente ne sont pas sur le même ordinateur ?

Statistiques de réponses au QCM

Ce chapitre est la base de la transmission de flux entre une application serveur et application cliente. Il vous est maintenant possible de transmettre tout ce que vous voulez entre les deux. Il est donc essentiel.
Notez que nous n'avons pas parler du cas des nombres réels (float, double, etc.) car c'est assez difficile de transmettre ces nombres entre deux applications tout en restant portable. Mais rien ne peut vous empêcher de convertir ces nombres en chaines de caractères ou encore en nombres entiers après les avoir multipliés par 1000 par exemple ;) .
Chapitre précédent Sommaire Chapitre suivant

Partager

35 commentaires pour "La transmission de flux"
Note moyenne : 3.54 / 4 (79 votes)
Pseudo Commentaire
Hors ligne Togea # Posté le 26/07/2011 à 14:43:21
Be cool
Avatar

Je trouve le tuto super ! Mais j'ai une question : il faut faire la fonction send et read pour chaque possibilité ! (si la variable est de 2 octet 3 octet 4 octet ect...)
Ou es-ce que j'ai mal compris ?
 
Hors ligne Kratos714 # Posté le 29/12/2011 à 02:40:05
Avatar

Études : Epitech Lyon

Pour le serveur, n'oubliez pas de fermer aussi la socket du client après avoir coupé la connexion avec shutdown ;)
Hors ligne lord-I # Posté le 17/03/2012 à 15:11:26
1.6 for ever
Avatar

Études : Université de Lille 1 - Sciences et Technologies

Peut-on utliser les fonction write et read à la place de send et recv ?
Hors ligne xcodexif # Posté le 27/03/2012 à 17:45:27

Pour ceux qui voudraient un petit coup de pouce pour des problèmes d'endianness, voici deux petites fonctions templates.
Pour envoyer :
Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
template <typename integer_t>
ssize_t sendsockint(socket_t sock, integer_t integer) {
	char* data = new char[sizeof(integer_t)];
    
	uint8_t i = 0;
	for (uint8_t bit = sizeof(integer_t)*CHAR_BIT; bit != 0; bit-=CHAR_BIT) {
		data[i] = (integer >> bit) & 0xFF;
	}
	
	return send(sock, data, sizeof(integer_t), NULL);
}

// Utilisation

uint64_t bigint = 55547222725;
sock_err = sendsockint(mon_socket, bigint);


Et pour recevoir :
Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
template <typename integer_t>
integer_t recsockint(socket_t sock) {
    	char* data = new char[sizeof(integer_t)];
    
	recv(sock, data, sizeof(integer_t), NULL);
	
	integer_t integer;
	
	uint8_t i = 0;
	for (uint8_t bit = sizeof(integer_t)*CHAR_BIT; bit != 0; bit-=CHAR_BIT) {
		integer |= data[i] << bit;
	}
	
	return integer;
}

// Utilisation

uint64_t bigint;
bigint = recsockint<uint64_t>(mon_socket);


Plus limité par les short et les long, qui peuvent en plus varier d'un ordi à l'autre :lol:
Vive la portabilité ! :D

J'ai pas encore testé... :-°
Hors ligne xcodexif # Posté le 27/03/2012 à 17:47:25

@lord-I

Bien sur un socket est un file descriptor ;)

Voir tous les commentaires