0x01. LA THEORIE
Une socket défini l'interface entre le système d'exploitation et les logiciels. Un logiciel qui est amenée à utiliser une socket aura accès à un type de réseau. La programmation réseau se fait donc via des socket, ensuite selon le type de réseau à atteindre, le paramètrage de la socket intervient. L'appel à une socket se fait généralement par inclusion d'une bibliothèque de fonctions.
Ordinateur -> Système d'exploitation -> Langage de programmation -> Socket -> Logiciel Windows -> Langage C -> #include <winsock.h> [...] -> Logiciel
0x02. SERVEUR
Passons à la pratique. Le programme source du serveur est celui-ci, vous pourrez remarquer la boucle infinie while(1) qui montre bien que le serveur est en écoute et donc en attente d'un client.
#include <time.h> // time, ctime #include <stdio.h> // printf #include <conio.h> // clrscr #include <winsock2.h> // accès aux sockets // Pour Visual C++ #pragma comment(lib, "ws2_32.lib") void main() { char buffer [255] ; time_t t; WSADATA WSAData; WSAStartup(MAKEWORD(2,0), &WSAData); SOCKET sock; // Déclataration des sockets SOCKET csock; // SOCKADDR_IN sin; // Déclaration des structures d'adressage (IP, Port, ...) SOCKADDR_IN csin; // /**** * La création d'un socket se fait grâce à la fonction * socket() : * * int socket(FAMILLE,TYPE,PROTOCOLE) * * FAMILLE représente la famille de protocole utilisé (AF_INET pour TCP/IP * utilisant une adresse Internet sur 4 octets : l'adresse IP ainsi qu'un * numéro de port afin de pouvoir avoir utiliser plusieurs sockets sur une même * machine, AF_UNIX pour les communications UNIX en local sur une même * machine, notamment pour les communications avec le serveur X) * TYPE indique le type de service (orienté connexion ou non : TCP ou UDP). * Dans le cas d'un service orienté connexion (c'est généralement le cas), * l'argument TYPE doit prendre la valeur SOCK_STREAM (communication par * flot de données). Dans le cas contraire (protocole UDP) le paramètre * TYPE doit alors valoir SOCK_DGRAM (utilisation de datagrammes, * blocs de données) protocole permettant de fournir le service désiré. * PROTOCOLE : Dans le cas de la suite TCP/IP il n'est pas * utile, on le mettra ainsi toujours à 0 La fonction socket() renvoie un * entier - un handle - qui correspond à un descripteur du socket nouvellement * créé et qui sera passé en paramètre aux fonctions suivantes. * En cas d'erreur, la fonction socket() retourne -1. * /***/ sock = socket(AF_INET, SOCK_STREAM, 0); /***/ sin.sin_addr.s_addr = INADDR_ANY; sin.sin_family = AF_INET; sin.sin_port = htons(4444); /*** * Après création du socket, il faut le lier à un point de communication * défini par une adresse et un port, c'est le rôle de la fonction bind() * Dans ce cas, on BIND l'adresse locale (0.0.0.0) accessible depuis l'extérieur /***/ bind(sock, (SOCKADDR *)&sin, sizeof(sin)); /***/ listen(sock, 0); clrscr(); printf("/nServer running.../n/n"); while(1) // On se met en écoute, tant que 1 est différent de 0... { int sinsize = sizeof(csin); // on récupère la taille de l'adresse if((csock = accept(sock, (SOCKADDR *)&csin, &sinsize)) != INVALID_SOCKET) // si la fonction 'accept' ne retourne pas la valeur INVALID_SOCKET // on affiche un message de bienvenue { memset(buffer,0,255); wsprintf(buffer,"welcome"); // on copie "welcome" dans buffer send(csock,buffer,255,0); // on envoie buffer au client via // la socket 'csock' time(&t); // on récupère le temps local // Du côté du serveur on affiche l'adresse IP du client et l'heure locale printf("new client connected: %s - time: %s", inet_ntoa(csin.sin_addr),ctime(&t)); } } }
0x03. CLIENT
Pour utiliser les socket en langage C, sous Windows, il faut inclure le ficheir de bibliothèque winsock2.h, winsock.h inclus eux-même dans windows.h. C'est grâce à ces entêtes que l'on peut créer et manipuler les sockets car les fonctions à utiliser se trouvent dedans. Nous allons voir comment coder le client du serveur ci-dessus. La source est suffisament commentée.
#include <string.h> // strlen #include <stdio.h> // printf, memset #include <conio.h> // getch() #include <winsock2.h> // connect, WSA, SOCKET #pragma comment(lib, "ws2_32.lib") void main() { char strIP [15] ; // variable qui va accueillir l'adresse ip // max. 15 caractères : 127.000.000.000 4x3+3=15 WSADATA WSAData; // Variable pour le support Winsock WSAStartup(MAKEWORD(2,0), &WSAData); // Initialisation du support Winsock SOCKET sock; // La socket - le support réseau - qui sera utilisé // pour la réception et la connexion. SOCKADDR_IN sin; // Socket de paramètrage char buffer [255] ; unsigned int iPort=4444; sock = socket(AF_INET, SOCK_STREAM, 0); // on créé notre socket selon le modèle de flux "chaine de caractère" printf("Adresse IP: "); // affichage de la demande de saisie de l'adresse ip du serveur scanf("%s",strIP); // on sauvegarde dans strIP l'adresse IP printf("Port: "); // de même pour le numéro de port scanf("%d",&iPort); // if(!iPort) iPort=4444; // par défaut on met 4444, si le port est nul clrscr(); printf("Connecting to %s...",strIP); // mise en forme... sin.sin_addr.s_addr = inet_addr(strIP); // on initiailise la socket sin.sin_family = AF_INET; // de paramètrage avec sin.sin_port = htons(iPort); // l'ip, le port et le type /**** * Voici la liste des type de protocol utilisable en C ( C++, C# ) * il s'agit du type de transport de donnée, par exemple AF_INET est le plus * utilisé car c'est celui qui utilise TCP/IP, UDP et ICMP (ping) pour * transférer les données d'un client vers un ma?tre. Concernant les autres * protocoles je vous renvoie à leur RFC (références, terme utilisé dans le * monde des réseaux) pour y avoir plus de détails. * * * Valeur * Constante numérique Brève description * ----------- ---------- ----------------------------------- * AF_UNIX 1 local to host (pipes, portals) * AF_INET 2 internetwork: UDP, TCP, etc. * AF_IMPLINK 3 arpanet imp addresses * AF_PUP 4 pup protocols: e.g. BSP * AF_CHAOS 5 mit CHAOS protocols * AF_NS 6 XEROX NS protocols * AF_IPX AF_NS IPX protocols: IPX, SPX, etc. * AF_ISO 7 ISO protocols * AF_OSI AF_ISO OSI is ISO * AF_ECMA 8 european computer manufacturers * AF_DATAKIT 9 datakit protocols * AF_CCITT 10 CCITT protocols, X.25 etc * AF_SNA 11 IBM SNA * AF_DECnet 12 DECnet * AF_DLI 13 Direct data link interface * AF_LAT 14 LAT * AF_HYLINK 15 NSC Hyperchannel * AF_APPLETALK 16 AppleTalk * AF_NETBIOS 17 NetBios-style addresses * AF_VOICEVIEW 18 VoiceView * AF_FIREFOX 19 Protocols from Firefox * AF_UNKNOWN1 20 Somebody is using this! * AF_BAN 21 Banyan * AF_ATM 22 Native ATM Services * AF_INET6 23 Internetwork Version 6 /****/ connect(sock, (SOCKADDR *)&sin, sizeof(sin)); // On se connecte en utilisant la socket et ses adressages associé (SOCKADDR_IN) // SOCKADDR_IN : SOCKet ADDRess INput // La socket 'sock' est utilisée pour les transferts de données selon le // protocol, alors que la socket 'sin' est utilisée pour les paramètres de // connexion, c'est à dire, l'hôte, le port. printf("Ok/n/n"); // Si on est connecté c'est : "Ok" memset(buffer,0,255); // Initialisation de buffer à 0 dans ses 255 cases recv(sock, buffer, sizeof(buffer), 0); // Réception des données provenant du serveur via notre socket 'sock' // Un client ne fait que de se connecter et recevoir. if(strlen(buffer)>4) // Il se peut parfois que Windows ou un programme utilise ce port // notamment quelques parefeu et retourne une valeur non signifiante, // on estimera que cette valeur a moins de 4 caractères elle ne vaut pas // la peine d'être affichée. { printf("Message from Server:\n\n%s\n\n",buffer); // Affichage du buffer getch(); // On attend une réaction de l'utilisateur } closesocket(sock); // Fermeture de la socket 'sock' WSACleanup(); // On réinitliase le support de communication de Windows // WSA : Windows Socket Application // WINSOCK : WINdows SOCKet }
0x04. SECURITE
En terme de sécurité il faut bien paramétrer son firewall afin qu'il ne laisse pas n'importe quel programme se connecter au réseau, car s'il n'est pas très difficile de faire un programme qui se connecte au réseau, pour un hacker il n'est pas difficile de faire un virus qui se connecte à notre insu aux réseaux. En terme de sécurité dans le programme à écrire il faut bien attention aux buffer overflow et également à tout type de débordement, que ce soit de la pile (stack) ou autre. Je ne ferais qu'un bref aperçu. Un bon principe de sécurité est de bloquer tout ce qui n'est pas connu, une politique restrictive de sécurité est toujours mieux même si elle se révèle contraignante à mettre en place sur un réseau personnel.
// Ce code n'est pas sécurisé, si la personne saisie une chaine de plus de 15 caractères char buff [15] ; scanf("%s",buff); // Il y a pour ça plusieurs méthode pour sécuriser le code, en voici quelques unes des plus simples: char buff [15] ; scanf("%15s",buff); char *buff; scanf("%s",buff);
0x05. CONCLUSION
Ce tutorial se termine ici. Voici une liste de lien qui ne peuvent qu'être utile afin comprendre plus en détail les socket ainsi que les sources des programmes :
Source du serveur
Source du client
Ainsi que des liens pour apprendre à utiliser les sockets :
Windows Socket 2.0
Asynchronous Server Socket Example
Programmation Socket en C sous Windows
Winsock par _SebF
Windows Sockets
=> Écrit par : Nicolas, le 05 décembre 2007