#include #include #include #include #include #include #define PORT 2000 void error(char *msg) { perror(msg); exit ( 1 ); } int main () { // ============================================================================= // creation de la socket // ============================================================================= // Il existe différents types de sockets et différents domaines d'adresses. // Lors de leur création, il faut donc spécifier ce que vous souhaitez // utiliser. Le domaine d'adresses pour communiquer via ``internet'' s'appelle // AF_INET. Le type de socket pour communiquer via le protocole TCP // s'appelle SOCK_STREAM. Dans ce TME, on utilise le protocole TCP. La // création de vos sockets s'effectuera donc via l'instruction C suivante: int sockfd = socket( AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { error("erreur d'ouverture de socket"); } // ============================================================================= // parametrage des ports et adresses du serveur // ============================================================================= // Lorsque votre socket est créée sur votre serveur, il faut lui affecter une // adresse et un numéro de port via la fonction bind (). Le premier argument // de bind est le descripteur de fichier que vous avez créé à l'étape // précédente (sockfd). Le deuxième est un pointeur sur une variable de type // générique sockaddr. Pour les sockets ``internet'', ce type s'instancie en: // // struct sockaddr_in { // sa_family_t sin_family; /* famille : AF_INET */ // in_port_t sin_port; /* le numéro de port */ // struct in_addr sin_addr; /* l'adresse internet */ // }; // Le troisième et dernier argument est la taille de cette variable. // // Il faut donc créer une variable server_addr de type sockaddr_in et indiquer // que son champ sin_family est AF_INET. Il faut également indiquer dans le // champ sin_port le numéro de port que vous voulez utiliser. Dans le TME, vous // utiliserez le port 2000. Toutefois, pour spécifier ce numéro, il faut utiliser // l'instruction htons(2000) qui normalise l'ordre des bits du nombre 2000. Il // faut enfin indiquer, dans le champ sin_addr, l'adresse à laquelle vos // clients devront se connecter pour accéder à votre serveur. Ce champ est de // type in_addr: // // typedef uint32_t in_addr_t; // struct in_addr { // in_addr_t s_addr; // }; struct sockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(2000); server_addr.sin_addr.s_addr = INADDR_ANY; // bind if ( bind ( sockfd, (struct sockaddr *) &server_addr, sizeof ( server_addr ) ) < 0 ) { error ("binding impossible"); } // ============================================================================= // listen // ============================================================================= // Il faut maintenant écouter les connexions des clients. Ici, il suffit // d'appliquer la fonction {\mytt listen ()} en lui passant en argument // sockfd et la taille de la file d'attente des clients (on peut accepter, par // exemple, 5 clients simultanément). listen ( sockfd, 5 ); // ============================================================================= // accept // ============================================================================= // La suite de votre programme consiste en l'acceptation des connexions de vos // clients grâce à la fonction accept (). Le prototype de cette fonction est: // // int accept( int sockfd, /* socket du serveur */ // struct sockaddr *addr, /* un pointeur sur l'adresse du client */ // socklen_t *addrlen ); /* la longueur de addr */ // // L'idée consiste donc à créer une variable client_addr de type sockaddr_in, // qui contiendra l'adresse IP et le numéro de port du client lorsque ce dernier // aura fait une tentative de connexion. Il faut également créer une variable // client_len de type socklen_t. // On passe alors des pointeurs sur les variables client_addr et client_len à // la fonction accept (), en n'oubliant pas de caster le pointeur sur // client_addr en un pointeur sur sockaddr. La fonction accept () retourne le // descripteur correspondant à la socket créée pour converser spécifiquement // avec le client. while ( 1 ) { struct sockaddr_in client_addr; socklen_t client_len; int client_sockfd = accept ( sockfd, (struct sockaddr*) &client_addr, &client_len ); if ( client_sockfd < 0 ) { error ( "erreur d'accept" ); } int nb = write ( client_sockfd, "Message de votre serveur : hello\n", 33 ); if ( nb < 0 ) { error ( "erreur d'ecriture vers le client" ); } else { printf ( "message : %d octets envoyes sur le port %d\n", nb, ntohs ( client_addr.sin_port ) ); } } return 0; }