Bonjour,
Je suis à réaliser une petite application en client/serveur (1/1) qui doit me permettre d'envoyer des informations concernant un bilan fonctionnel pour obtenir des ratios.
Partie gestion financière mise à part, j'ai un problème parce que je n'arrive pas à passer un tableau à une fonction puis à le récupérer.
A la base, j'avais fait mon code comme un gros paquet d'instruction... Un point d'entrée main et voilà
J'ai donc souhaité faire des fonctions afin de découper mon code en bloc lisibles et compréhensibles... Ce que j'essaie de faire mais j'ai énormément de mal avec la notion de pointeurs et références en C...
Voici mon code :
-- une archive se trouve à la fin du message
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
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 /************************************************* ** Nom du fichier : client.h ** Deallyra ** ** Entête de l'application cliente de calcul des ** différents ratios à partir du bilan fonctionnel. ** *****************************************************/ /** * Fonction de vérification de passage d'une adresse IP à l'application via * le paramètre argv. * Dans le cas où le paramètre fourni ne serait pas une IP, l'application se * termine. * * Non utilisée, nom du serveur servant à la connexion * *@param char *@return void */ //void verifierCommandeLancement(char*); /** * Fonction de requête de saisie des différentes valeurs du Bilan fonctionnel *@param int *@return int */ int bilan (int); // @todo /** * Fonction de création et connexion d'un socket entre deux stations *@param int *@return void */ void creationConnexionSocket (int); /** * Fonction de requête de saisie des différentes valeurs du Bilan fonctionnel *@param long* *@return long* */ long* saisieBilan(long*);
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188 /************************************************* ** Nom du fichier : client.c ** Deallyra ** ** Fichier corps de l'application cliente de calcul des ** différents ratios à partir du bilan fonctionnel. ** *****************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> /* #include <linux/types.h> #include <sys/socket.h> */ #include <netdb.h> #include "client.h" //Port d'écoute du serveur #define PORT 20000 //Taille maximale pour l'envoi des données d'un socket #define MAX_LENGTH 256 /** * Fonction de vérification de passage d'une adresse IP à l'application via * le paramètre argv. * Dans le cas où le paramètre fourni ne serait pas une IP, l'application se * termine. * * Non utilisée, nom du serveur servant à la connexion * *@param char *@return void */ /*void verifierCommandeLancement(char* adresseIP) { * /!\ * Il faudrait vérifier l'IP autrement qu'en la parsant. * regexp possible en C ? * //On indique la position du caractère par rapport à la "chaine" de l'IP. int i = 0; //Simulation d'un type booléen. 0=> False; 1=> True; int estUneAdresseIP = 1; //On vérifie les octets. while(estUneAdresseIP == 1 && i <= 14) { //On récupère un octet. int octet = adresseIP[i]*100+adresseIP[i+1]*10+adresseIP[i+2]; //Est-il compris entre 0 et 255 ? if(octet <= 0 || octet >= 255) { estUneAdresseIP = 0; } i += 4; } //On vérifie les séparateurs (points) entre les octets. i = 3; while(estUneAdresseIP == 1 && i <= 11) { //Est-il compris entre 0 et 255 ? if(strcmp(adresseIP[i], ".") != 0) { estUneAdresseIP = 0; } i += 4; } //Si le paramètre fourni n'est pas correct, l'application se termine. if(estUneAdresseIP == 0) { perror( ">> Il faut fournir une adresse IP a l'application" ); exit( 1 ); } } */ /** * Fonction de saisie des éléments du bilan fonctionnel *@param int *@return int */ long* saisieBilan(long* input) { printf( "\n\tETABLISSEMENT DU BILAN FONCTIONNEL\n\n" ); printf( "(Veuillez entrer les montants)\n" ); //Saisie des différentes valeurs de l'actif et du passif printf( "\n- Actif -\n" ); printf( "Emplois Stables: " ); scanf( "%ld", &input[0] ); printf( "Actifs Circulants d'Exploitation: " ); scanf( "%ld", &input[1] ); printf( "Actifs Circulants Hors Exploitation: " ); scanf( "%ld", &input[2] ); printf( "Trésorerie de l'Actif: " ); scanf( "%ld", &input[3] ); printf( "\n- Passif -\n" ); printf( "Ressources Stables: " ); scanf( "%ld", &input[4] ); printf( "Dettes d'Exploitation: " ); scanf( "%ld", &input[5] ); printf( "Dettes Hors Exploitation: " ); scanf( "%ld", &input[6] ); printf( "Trésorerie du Passif: " ); scanf( "%ld", &input[7] ); return input; } /** * Fonction de requête de saisie des différentes valeurs du Bilan fonctionnel *@param int *@return int */ int bilan(int sock) { //Variable recevant les données à envoyer au serveur. char data[MAX_LENGTH]; //Tableau recevant les différentes saisies du Bilan Fonctionnel long input[8]; //Appel à la fonction de saisie du bilan input = saisieBilan(input); //Envoi des données au serveur //Longueur de la donnée à envoyer || Sert de vérification également int dataLength = 0; //On "ré-initialise" la variable data à vide. strcpy( data, "" ); //Pour chacune des données (du tableau) à envoyer int i = 0; while((i < 8) && (dataLength != -1) && (strcmp( data, "ERROR" ) != 0)) { //On place la donnée dans la variable tampon data sprintf( data, "%ld", input[i] ); //Si l'écriture dans le socket ne se passe pas bien if (write( sock, data, strlen( data ) ) == -1) { perror( ">> Erreur: la fonction write() a renvoye une erreur." ); dataLength = -1; } //La donnée est transmise au serveur else { //On attend l'accusé de réception du serveur dataLength = read( sock, data, sizeof( char[MAX_LENGTH] ) ); //Tant que l'on ne reçoit rien, on continue à attendre la réponse du serveur. while (dataLength == 0) { dataLength = read( sock, data, sizeof( char[MAX_LENGTH] ) ); } //Nous n'avons pas pu lire la réponse du serveur if (dataLength == -1) { perror( ">> Erreur: la fonction read() a renvoye une erreur." ); } } i++; } //La fonction write() ou read() a envoyé une erreur. //Le traitement n'a pas été à terme if (dataLength != -1) { perror( ">> Erreur: le serveur a renvoye une erreur." ); exit( 1 ); } else { printf( "\n\tResultat des calculs\n\n" ); //On lit la réponse du serveur while (read( sock, data, sizeof( char[MAX_LENGTH] ) ) > 0) { printf( "%s", data ); } return 1; } }et voici le makefile
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 /************************************************* ** Nom du fichier : main.c ** Deallyra ** ** Entrée du programme de l'application cliente de calcul des ** différents ratios à partir du bilan fonctionnel. ** *****************************************************/ int main (int argc, char **argv) { //Variable permettant de vérifier que le descripteur du soket est créé int connectSocket; //Structure permettant de préparer l'adressage de la machine distante (serveur) struct sockaddr_in connectInfos; //Structure permettant de récupérer des infos sur la machine distante (serveur) struct hostent *serverInfos; //Port d'écoute du serveur #define PORT 20000 //Taille maximale pour l'envoi des données d'un socket #define MAX_LENGTH 256 //Fonction non utilisée pour le moment //verifierCommandeLancement(char argv[0]); //Création du socket // socket(int domaine, int type, int protocole); //Domaine => Famille de protocole, IP dans notre cas //Type => TCP (SOCK_STREAM) ou UDP (SOCK_DGRAM) //Protocole => A zéro généralement if ((connectSocket = socket( AF_INET, SOCK_STREAM, 0 )) == -1) { perror( ">> Erreur: impossible de creer le socket." ); exit( 1 ); } //On récupère le nom du serveur, paramètre d'entrée de l'application serverName = argv[1]; //Récupération des informations sur la machine distante (serveur) if ((serverInfos = gethostbyname(serverName)) == NULL) { perror( ">> Erreur: impossible de recuperer des informations sur le serveur." ); exit( 1 ); } //Famille du protocole et son port bcopy( (char *)serverInfos->h_addr, (char *)&connectInfos.sin_addr, serverInfos->h_length); connectInfos.sin_family = serverInfos->h_addrtype; // ou connectInfos.sin_family = AF_INET connectInfos.sin_port = htons( PORT ); // htons permet de faire les conversions necessaires a la portabilite du code //Connexion au serveur avant de faire les traitements if (connect( connectSocket, (struct sockaddr *)&connectInfos, sizeof( struct sockaddr_in ) ) == -1) { perror( ">> Erreur: impossible de connecter le socket au serveur." ); exit( 1 ); } //Etablissement du Bilan bilan( connectSocket ); //On ferme le socket dont le descriptif est passé en paramètre close( connectSocket ); return 0; }
Et donc mon erreur est la suivante :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 CC=gcc CFLAGS=-Wall -Wextra -O -Wstrict-prototypes -Wunreachable-code -g LDFLAGS= EXEC=chatTCP_client SRC= $(wildcard *.c) OBJ= $(SRC:.c=.o) all: $(EXEC) chatTCP_client: $(OBJ) @$(CC) -o $@ $^ $(LDFLAGS) main.o: client.h %.o: %.c @$(CC) -o $@ -c $< $(CFLAGS) .PHONY: clean mrproper clean: rm -rf *.o mrproper: clean rm -rf $(EXEC)
Ce qui concerne les lignes suivantes :client.c: Dans la fonction «bilan» :
client.c:127: erreur: incompatible types in assignment
client.c:146: attention : déclaration implicite de la fonction « «write» »
client.c:155: attention : déclaration implicite de la fonction « «read» »
make: *** [client.o] Erreur 1
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
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 /** * Fonction de saisie des éléments du bilan fonctionnel *@param int *@return int */ long* saisieBilan(long* input) { printf( "\n\tETABLISSEMENT DU BILAN FONCTIONNEL\n\n" ); printf( "(Veuillez entrer les montants)\n" ); //Saisie des différentes valeurs de l'actif et du passif printf( "\n- Actif -\n" ); printf( "Emplois Stables: " ); scanf( "%ld", &input[0] ); printf( "Actifs Circulants d'Exploitation: " ); scanf( "%ld", &input[1] ); printf( "Actifs Circulants Hors Exploitation: " ); scanf( "%ld", &input[2] ); printf( "Trésorerie de l'Actif: " ); scanf( "%ld", &input[3] ); printf( "\n- Passif -\n" ); printf( "Ressources Stables: " ); scanf( "%ld", &input[4] ); printf( "Dettes d'Exploitation: " ); scanf( "%ld", &input[5] ); printf( "Dettes Hors Exploitation: " ); scanf( "%ld", &input[6] ); printf( "Trésorerie du Passif: " ); scanf( "%ld", &input[7] ); return input; } /** * Fonction de requête de saisie des différentes valeurs du Bilan fonctionnel *@param int *@return int */ int bilan(int sock) { //Variable recevant les données à envoyer au serveur. char data[MAX_LENGTH]; //Tableau recevant les différentes saisies du Bilan Fonctionnel long input[8]; //Appel à la fonction de saisie du bilan input = saisieBilan(input); (...)
J'aimerai bien que l'on m'apprenne à pécher et que je comprenne enfin comment marche ces "adorables" pointeurs... J'ai beau lire cours et tuto je ne comprends pas...
long* peut dire qu'on veut passer un tableau de long comme dire qu'on passe un pointeur vers un long... je la fais comment la différence ?
C'est assez nébuleux pour moi...
Merci à vous pour toute aide que vous pourrez m'aporter.
PS : voici une archive du code source
Partager