Changes between Initial Version and Version 1 of IOC20_T05-0


Ignore:
Timestamp:
Feb 28, 2020, 7:01:14 AM (5 years ago)
Author:
franck
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • IOC20_T05-0

    v1 v1  
     1= Modèle client-serveur
     2
     3== Objectif de la séance
     4
     5Le but de cette séance est d'expérimenter le modèle client-serveur au dessus de TCP-IP au travers de la programmation d'un jeu.
     6Le TP va se dérouler sur les PC de développement. Nous verrons plus tard deux autres applications du modèle client-serveur avec le serveur HTTP et le protocole MQTT qui permet l'échange d'informations entre des capteurs WIFI et une station de base suivant un modèle client-broker.
     7
     8Pour aujourd'hui, vous allez programmer deux applications. La première met en œuvre N clients TCP et 1 serveur TCP. La seconde application mettra en œuvre N client-serveurs et 1 serveur.
     9
     10== Mise en œuvre du modèle client-serveur sur une application de vote
     11
     12Pour présenter le modèle client-serveur, nous allons suivre un exemple que vous allez devoir comprendre et à partir duquel vous allez devoir créer une nouvelle applications.
     13
     141. Vous devez commenter l’exemple dans le code en vous aidant de la documentation. Le but de ces commentaires est de vous forcer à lire la documentation pour les quelques fonctions présentes dans l’exemple.
     152. Vous allez créer une nouvelle application permettant de recueillir le vote de personne concernant le choix de l’heure d’hiver ou d’été. Vous avez deux programmes à écrire. Le premier permet de voter, c’est le client TCP. Le second permet de recueillir le vote, c’est le serveur TCP.
     16   
     17* **L'application "client"
     18  * Paramètres :
     19    * L’adresse IP du serveur
     20    * Le numéro de port de l’application serveur
     21    * Le nom de la personne
     22    * Le vote avec deux possibilités : été ou hiver
     23  * Comportement attendu :
     24    * Le client crée un socket, se connecte et envoi son vote au serveur.
     25    * Le serveur lui renvoie un acquittement de son vote.
     26
     27* **L'application "serveur"
     28  * Paramètres :
     29    * Le numéro du port d’écoute.
     30  * Comportement attendu :
     31    * Le serveur un socket et écoute
     32    * Lorsqu’un client se connecte, il vérifie que le client n’a pas encore voté
     33      * Si ok, le serveur envoie le message « a voté »
     34      * Si ko, le serveur envoie le message « erreur, vote déjà réalisé »
     35
     36* **Remarques sur le choix du port d'écoute
     37  * Le port d'écoute est imposé par le serveur et client doit connaître ce numéro pour lui envoyer des messages.
     38  * __Si c'est un test local__:
     39    * Dans un terminal : ./server 32000
     40    * Dans un autre terminal : ./client localhost 32000
     41  * __Si c'est un test distant__:
     42    * Il suffit de remplacer localhost par l'adresse IP du serveur. vous pouvez connaitre votre adresse IP avec la commande `hostname -I`
     43
     44** Schéma de principe d'un échange client-serveur avec le protocole TCP (connecté)
     45   [[Image(htdocs:png/client-serveur.png,300px,nolink)]]
     46   
     47Illustration dans un programme où le client envoie un message à un serveur (qui ne lui répond pas).
     48
     49** server.c :
     50{{{
     51#!c
     52/* A simple server in the internet domain using TCP The port number is passed as an argument */
     53#include <stdio.h>
     54#include <stdlib.h>
     55#include <string.h>
     56#include <unistd.h>
     57#include <sys/types.h>
     58#include <sys/socket.h>
     59#include <netinet/in.h>
     60
     61#include <netdb.h>
     62#include <arpa/inet.h>
     63
     64void error(const char *msg)
     65{
     66        perror(msg);
     67        exit(1);
     68}
     69
     70int main(int argc, char *argv[])
     71{
     72        int sockfd, newsockfd, portno;
     73        socklen_t clilen;
     74        char buffer[256];
     75        struct sockaddr_in serv_addr, cli_addr;
     76        int n;
     77       
     78        if (argc < 2) {
     79                fprintf(stderr, "ERROR, no port provided\n");
     80                exit(1);
     81        }
     82
     83        // 1) on crée la socket, SOCK_STREAM signifie TCP
     84
     85        sockfd = socket(AF_INET, SOCK_STREAM, 0);
     86        if (sockfd < 0)
     87                error("ERROR opening socket");
     88
     89        // 2) on réclame au noyau l'utilisation du port passé en paramètre
     90        // INADDR_ANY dit que la socket va être affectée à toutes les interfaces locales
     91
     92        bzero((char *) &serv_addr, sizeof(serv_addr));
     93        portno = atoi(argv[1]);
     94        serv_addr.sin_family = AF_INET;
     95        serv_addr.sin_addr.s_addr = INADDR_ANY;
     96        serv_addr.sin_port = htons(portno);
     97        if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
     98                error("ERROR on binding");
     99
     100
     101        // On commence à écouter sur la socket. Le 5 est le nombre max
     102        // de connexions pendantes
     103
     104        listen(sockfd, 5);
     105        while (1) {
     106                newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
     107                if (newsockfd < 0)
     108                    error("ERROR on accept");
     109
     110                bzero(buffer, 256);
     111                n = read(newsockfd, buffer, 255);
     112                if (n < 0)
     113                    error("ERROR reading from socket");
     114
     115                printf("Received packet from %s:%d\nData: [%s]\n\n",
     116                       inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port),
     117                       buffer);
     118
     119                close(newsockfd);
     120        }
     121
     122        close(sockfd);
     123        return 0;
     124}
     125}}}
     126
     127** client.c
     128{{{
     129#!c
     130#include <stdio.h>
     131#include <stdlib.h>
     132#include <unistd.h>
     133#include <string.h>
     134#include <sys/types.h>
     135#include <sys/socket.h>
     136#include <netinet/in.h>
     137#include <netdb.h>
     138
     139void error(const char *msg)
     140{
     141        perror(msg);
     142        exit(0);
     143}
     144
     145int main(int argc, char *argv[])
     146{
     147        int sockfd, portno, n;
     148        struct sockaddr_in serv_addr;
     149        struct hostent *server;
     150
     151        char buffer[256];
     152
     153        // Le client doit connaitre l'adresse IP du serveur, et son numero de port
     154        if (argc < 3) {
     155                fprintf(stderr,"usage %s hostname port\n", argv[0]);
     156                exit(0);
     157        }
     158        portno = atoi(argv[2]);
     159
     160        // 1) Création de la socket, INTERNET et TCP
     161
     162        sockfd = socket(AF_INET, SOCK_STREAM, 0);
     163        if (sockfd < 0)
     164                error("ERROR opening socket");
     165
     166        server = gethostbyname(argv[1]);
     167        if (server == NULL) {
     168                fprintf(stderr,"ERROR, no such host\n");
     169                exit(0);
     170        }
     171
     172        // On donne toutes les infos sur le serveur
     173
     174        bzero((char *) &serv_addr, sizeof(serv_addr));
     175        serv_addr.sin_family = AF_INET;
     176        bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
     177        serv_addr.sin_port = htons(portno);
     178
     179        // On se connecte. L'OS local nous trouve un numéro de port, grâce auquel le serveur
     180        // peut nous renvoyer des réponses, le \n permet de garantir que le message ne reste
     181        // pas en instance dans un buffer d'emission chez l'emetteur (ici c'est le clent).
     182
     183        if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
     184                error("ERROR connecting");
     185
     186        strcpy(buffer,"Coucou Peri\n");
     187        n = write(sockfd,buffer,strlen(buffer));
     188        if (n != strlen(buffer))
     189                error("ERROR message not fully trasmetted");
     190
     191        // On ferme la socket
     192
     193        close(sockfd);
     194        return 0;
     195}
     196}}}
     197
     198** Makefile
     199
     200{{{
     201#!make
     202CFLAGS = -Wall -Werror
     203dep : server client usage
     204all : clean dep
     205clean :
     206        -rm server client
     207usage:
     208        @echo ""
     209        @echo "Usage :"
     210        @echo "    On the server computer, start the server:"
     211        @echo "       ./server port"
     212        @echo "    On the client computer, start the client:"
     213        @echo "       ./client ipserver portserver"
     214        @echo ""
     215}}}
     216
     217== Programmation d'un jeu
     218
     219