[langage C] Problème client/serveur

legyptien Messages postés 420 Statut Membre -  
 djessika -
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!
Configuration: Windows Vista
Firefox 2.0.0.11

9 réponses

  1. Char Snipeur Messages postés 10112 Date d'inscription   Statut Contributeur Dernière intervention   1 331
     
    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
  2. legyptien Messages postés 420 Statut Membre 9
     
    ok merci a toi char snipeur.
    0
  3. legyptien Messages postés 420 Statut Membre 9
     
    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
  4. legyptien Messages postés 420 Statut Membre 9
     
    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
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. Char Snipeur Messages postés 10112 Date d'inscription   Statut Contributeur Dernière intervention   1 331
     
    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
  7. legyptien Messages postés 420 Statut Membre 9
     
    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
  8. Char Snipeur Messages postés 10112 Date d'inscription   Statut Contributeur Dernière intervention   1 331
     
    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
  9. legyptien Messages postés 420 Statut Membre 9
     
    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
  10. djessika
     
    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