[langage C] Problème client/serveur

Fermé
legyptien Messages postés 382 Date d'inscription lundi 19 novembre 2007 Statut Membre Dernière intervention 23 avril 2022 - 21 déc. 2007 à 02:08
 djessika - 28 oct. 2008 à 12:57
Bonjour,

j ai un programme en C qui est:

un serveur echo retourne la chaine de caracteres qu il recoit. Il faut que je le modifie pour qu il retourne l adresse IP du client ainsi que son TCP.
Je sais que je dois utiliser la fonction "getpeername" et "inet_ntoa" qui utilise une structure de donnees de type sockaddr_in.

Voici les programmes echoclient et echoserveur mais il faut modifier que echoserveur(je sais pas comment j ajoute une piece jointe donc je colle mon programme en C que j ai ouvert avec "notepad" j espere qu il a pas modifier le contenu vu que c est du C):

ECHOCLIENT:
//
// Socket client using TCP
//

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stream.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>

#define MAXLEN 256

// ---------------------------------------------------------------------
// This function:
// - reads a string from std input (until '\n')
// - writes it to the socket
// - receives the copy through the socket
// - writes it back to the std output
// ---------------------------------------------------------------------
void str_cli(int sockfd)
{
char ws[MAXLEN];
char rs[MAXLEN];
int n_bytes, n_written, n_read;

// read the string to send
cout << "Please enter a string (no spaces)" << endl;
cin >> ws;
n_bytes = strlen(ws)+1;

// write on socket
n_written = write(sockfd, ws, n_bytes);

// see if you missed some characters
if (n_written < n_bytes)
fprintf(stderr, "Client warning: incomplete string sent\n");

// read the answer from the socket
n_read = read(sockfd, rs, MAXLEN);

// see if you lost some more characters on the way back
if (n_read < n_written)
fprintf(stderr, "Client warning: incomplete string received\n");

// writes the received string
cout << "This is the reply that I got back from the other side:" << endl;
cout << rs << endl;
}



// ---------------------------------------------------------------------
// main
// ---------------------------------------------------------------------
main (int argc, char* argv[])
{

int sockfd, clilen;
struct sockaddr_in serv_addr;

// check command line
if (argc < 3) {
cout << "Usage: echoClient <server port number> <server hostname>" << endl;
return(0);
}

// port number is given as first argument
const int serv_port = atoi(argv[1]);

// retrieve host information from name
struct hostent* hptr = gethostbyname(argv[2]);
if (hptr == NULL) {
cout << "echoClient: Error in gethostbyname(), "
<< "please check server host name" << endl;
return(0);
}

// look in address list
char** addrlist = hptr->h_addr_list;
struct in_addr* aptr;

aptr = (struct in_addr*) addrlist[0];
char* serv_ip = inet_ntoa(*aptr);

// Fill in the structure with the server address
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(serv_ip);
serv_addr.sin_port = htons(serv_port);

// Open a TCP socket
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
fprintf(stderr, "Client: error, cannot open stream socket\n");
return(0);
}


// Connect to the server
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
{
fprintf(stderr, "Client: error, cannot connect to server\n");
return(0);
}


// send the request and exit
str_cli(sockfd);

close(sockfd);
return(0);
}



ECHOSERVEUR:
//
// Socket server using TCP
//

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stream.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

// #define SERV_TCP_PORT 6321
// #define SERV_HOST_ADDR "193.55.114.167" /* faron.eurecom.fr */

#define MAXLEN 255

// This function:
// - reads a string from a socket
// - writes it back to the same socket
void str_echo(int sockfd)
{
char s[MAXLEN];
int n_written, n_read;

// read the string from socket
n_read = read(sockfd, s, MAXLEN);

// print the received string
cout << "String read: " << s << endl;

// write back
n_written = write(sockfd, s, n_read);

// see if you missed some characters
if (n_written < n_read)
fprintf(stderr, "Server warning: incomplete string sent\n");
}



main (int argc, char* argv[])
{

int sockfd, newsockfd;
socklen_t clilen;
struct sockaddr_in cli_addr, serv_addr;

// server port number
if (argc < 2) {
cout << "Argument: server port number" << endl;
return(0);
}
int serv_port = atoi(argv[1]);

// Open a TCP socket
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
fprintf(stderr, "Error in server: can't open socket\n");
return(0);
}

// bind the local address with specified port number
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(serv_port);

if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
{
fprintf(stderr, "Error in server: can't bind local address\n");
return(0);
}

listen(sockfd,1);

for (;;) {

// Wait for connections from clients.
// Iterative server.
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

if (newsockfd < 0)
{
fprintf(stderr, "Server: accept error.\n");
return(0);
}

// Process the request.
cout << "Request received, ..." << endl;
str_echo(newsockfd);

// close the socket while waiting
close(newsockfd);
}

// close listening socket
close(sockfd);
}

MERCI beaucoup de votre aide, c est tres important!

9 réponses

Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
21 déc. 2007 à 08:40
l'adresse IP du client est contenu dans la structure sockaddr qui est passé lors du accept. c'est le membre sin_addr.
Donc, il suffit de passer cette structure à str_echo().
ensuite, tu récupère la chaine de caractère avec char* inet_ntoa((sockaddr_in).sin_addr) que tu n'a plut qu'a concaténer dans ton s.
Et voilà ! l'adresse TCP, je ne sais pas ce que c'est;
0
legyptien Messages postés 382 Date d'inscription lundi 19 novembre 2007 Statut Membre Dernière intervention 23 avril 2022 9
21 déc. 2007 à 11:20
ok merci a toi char snipeur.
0
legyptien Messages postés 382 Date d'inscription lundi 19 novembre 2007 Statut Membre Dernière intervention 23 avril 2022 9
1 janv. 2008 à 21:14
en fait, apres avoir bien etudié le code, j ai encore des questions (toutes pour le programme echo_server):
Dans le programme "echoserveur", je dois faire inet_ntoa(cli_addr.sin_addr) juste apres le "accept" et le resultat renvoyé sera l adresse IP du client sous le bon format si j'ai bien compris. Mais je peux aussi utiliser la fonction getpeername:

int getpeername(int s, struct sockaddr *name, socklen_t *namelen) qui est cencé renvoyer l adresse IP et le port TCP correspondant a la socket s.

1) quel est la difference entre gatpeername et inet_ntoa puisque les 2 nous donne l adresse IP (à part le fait que le getpeername renvoi aussi le port TCP)

2) Dans toutes les documentations on voit " int getpeername(...) " , comment il peut renvoyer 2 choses, il faut une structure pour ca.C'est le int que je comprends pas.
en definitive, ces 2 questions montrent que j ai pas bien compris l'utilité ET la maniere de me servir de getpeername.

3)Supposons que tout se passe bien jusqu au :
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
{
fprintf(stderr, "Error in server: can't bind local address\n");
return(0);
}
et que le bind se passe mal pour une raison quelconque, on va "imprimer" error in server et quitter le programme mais le socket qui etait ouvert depuis tout a l heure restera ouvert ? donc il faudrait avant le return "close(socket", qu est ce que vous en pensez? Et ce serait pareil pour un peu plus loin si le accept se passe mal , il faut faire un close??

4)D apres ce que j ai compris "newsockfd" est là pour chaque client. et des qu on a fait "str_echo(newsockfd)" on ferme newsockfd.Ca ok.Mais sockfd est le socket chargé de la connexion, on devrait fermer ce socket à un moment donné? si la reponse est "non" alors ma ligne close(sockfd) ne sert à rien. Si la reponse est oui alors il y a un probleme parce que quand je regarde mon programme, on sort jamais du for(;;) donc on fait jamais close(sockfd)!!!!
En resumé le getpeername et les fermetures de sockets sont pas super clair à mes yeux. Apres ca je pense que j'aurai plus de question.

je vous remercie d avance de m'avoir lu jusqu au bout.
0
legyptien Messages postés 382 Date d'inscription lundi 19 novembre 2007 Statut Membre Dernière intervention 23 avril 2022 9
1 janv. 2008 à 22:32
La question 2 n'a plus lieu d'etre car getpeername renvoi 0 si l'adresse a bien été charger dans name avec int getpeername(int s, struct sockaddr *name, socklen_t *namelen). En fait getpeername ne renvoie pas l adresse IP , il charge dans une structure.

Tout bien reflechi le getpeername n est pas utile parce que grace au "accept " on dispose des informations client donc la question 1 est resolu aussi mais une confirmation de votre part ma rassurerai...


merci à vous.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
3 janv. 2008 à 10:15
inet_ntoa() est une fonction de conversion de l'adresse IP écrite en "langage machine" vers une écriture lisible par un homme. Elle ne fait appel à aucune fonction réseau. getpeername(), va à partir du socket aller récupérer la structure sock_addr.
je ne pense pas que ça soit utile d'utiliser getpeername(), car il me semble que le port est inclu dans la structure sock_addr.
Pour le reste, je ne sais pas trop. Je pense que le socket doit être libérer automatiquement à la fin, ou éventuellement par l'OS.
0
legyptien Messages postés 382 Date d'inscription lundi 19 novembre 2007 Statut Membre Dernière intervention 23 avril 2022 9
3 janv. 2008 à 12:54
salut, désolé je lis plein de truc sur client/serveur mais j ai encore des questions voila le bind:
1)
bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) et le bind est definie comme ceci :

int bind(int sockfd, struct sockaddr *my_addr, int addrlen); le second argument est un pointeur sur structure (qui est du type sockaddr) . jusqu a la c bon.
quand on appel cette fonction le second argument doit etre une adresse puisque dans la definition du bind c est un pointeur (meme si il pointe sur une structure) en fait moi j aurais vu un truc comme ca:

bind(sockfd, &serv_addr, sizeof(serv_addr)) puisqu un pointeur on doit toujours lui passer une adresse en parametre.

2)"sizeof" d une structure je vois pas ce que c est , c est ni le nombre d elements qui compose cette structure ni le "cumule" de la place que prend chaque elements de cette structure puisque j ai testé ca

int main (void)
{
struct sockaddr_in a;
printf("la taille de a est %d \n",sizeof(a));
return(0);
}
ca me donne 16 . je sais que toutes ces questions (sur les pointeurs , les structures etc..) sont basiques , c est des lacunes sur le langage C et pas sur la programation client/serveur...
0
Char Snipeur Messages postés 9813 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 298
3 janv. 2008 à 16:13
Comme tu le dit toi même, ces questions n'ont rien à faire dans ce message, ouvre en un autre on y répondra tout autant. (l'interet est pour la recherche des messages plus tard)
Pour sizeof, regarde là : https://en.cppreference.com/w/cpp/keyword/sizeof
ça renvoie bien la taille en octet. et pourquoi la taille de a ne serai pas 16 ?
Pour le 1), il n'y a pas de question, je ne voi pas ce qui t'embete. Ou alors, tu ne comprend pas le (struct sockaddr *).
&serv_addr est de type "struct sockaddr_in*", ok ? seulement dans bind il faut passer un "sockaddr*", donc on fait un cast sauvage, comme on aurai pu faire :
int f(int* t){...}
float a=6465;
int i=f((int*)&a);
J'espère avoir deviner ta question.
0
legyptien Messages postés 382 Date d'inscription lundi 19 novembre 2007 Statut Membre Dernière intervention 23 avril 2022 9
3 janv. 2008 à 16:39
nickel tu as repondu a mes 2 questions et tu as bien deviné ma 1ere question. pour ce qui est du cast sauvage ,c est pas net mais j ai pas encore tapper cast sauvage sur google et je ne me suis pas documenter la dessus. La prochaine fois je ferais un post à part si je sorts un peu du sujet.

merci à toi ;)
0
bonjour,
en utilisant le langage C (les socket) je vais réaliser une application client/serveu qui parmet au serveurs d'afficher le message "salut", svp aidez moi!!
0