Sockets File - Plateforme e-learning Moodle de l`INSA de Rouen
Transcription
Sockets File - Plateforme e-learning Moodle de l`INSA de Rouen
Informatique Répartie Les Sockets Alexandre Pauchet BO.B.RC.18 – [email protected] Introduction Définition Un socket est un port de communication ouvert permettant de faire passer des flux C'est une interface entre la couche transport et les couches applicatives du modèle OSI La communication est en point à point en mode client-serveur, bi-directionnelle, en mode connecté (TCP) ou non connecté (UDP) 3 Communication point à point bidirectionnelle ● Un socket désigne l'extrémité d'une connexion ● Un socket est associé à un port ● La connexion établie, la communication est similaire à une écriture de fichier (Tiré de [1]) 4 Modes de connexion (Tiré de [1]) Mode connecté (TCP) : une liaison préalable aux données est établie ● Mode non connecté (UDP) : aucune liaison initiale n'est établie, chaque message est envoyé individuellement ● 5 Comparaison modes connecté / non connecté Avantages du mode non connecté : Pas de connexion à établir entre le client et le serveur Rapide Avantages du mode connecté : Fiable Séquencement des messages 6 Sockets en C Création d’un socket en C Les librairies : #include <sys/types.h> #include <sys/socket.h> Création d’un socket : int socket(int domain, int type, Retourne -1 si erreur int protocol) Familles de Sockets : - local : PF_LOCAL - internet : PF_INET Types de communication : - connecté : SOCK_STREAM - non connecté : SOCK_DGRAM Protocoles : - TCP : IPPROTO_TCP - UDP : IPPROTO_UDP - local : 0 8 Création d’un socket en C Table des correspondances : Domain PF_LOCAL PF_LOCAL PF_INET PF_INET Socket Type SOCK_STREAM SOCK_DGRAM SOCK_STREAM SOCK_DGRAM Protocol 0 0 IPPROTO_TCP IPPROTO_UDP Description Socket local avec connexion Socket local sans connexion Socket internet basé sur TCP Socket Internet basé sur UDP Exemples : int s1, s2; s1 = socket(PF_LOCAL, SOCK_DGRAM, 0); s2 = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 9 Lier un socket à une adresse et à un port Indispensable côté serveur, facultatif côté client Spécification de l'adresse : int bind(int socketid, l’identifiant de socket valeur retournée par socket() Retourne -1 si erreur struct sockaddr *addr, int addrlen) adresse locale (EndPoint) longueur en octets de l ’adresse 10 La structure d’adresse Chaque protocole a son format d’adresse, mais struct sockaddr est générique : struct sockaddr { u_short sa_family; char sa_data[14]; } AF_LOCAL, AF_INET, etc. l’adresse proprement dite Dans la pratique on utilise des variables dont le type correspond au protocole qu’on utilise, par exemple : struct sockaddr_in (AF_INET) 11 La structure d’adresse Les deux structures d’adresse les plus utilisées : Unix (défini dans sys/un.h): struct sockaddr_un { sa_family_t sun_family; char sun_path[108]; } AF_LOCAL ou AF_UNIX Chemin Internet (défini dans netinet/in.h): Port (conversion nécessaire !) inutilisé !! struct sockaddr_in { sa_family_t sin_family; unit16_t sin_port; struct in_addr sin_addr; unsigned char sin_zero[8]; } AF_INET Adresse IP struct in_addr { uint32_t s_addr } 12 La structure d’adresse Exemple : struct sockaddr_in adresse.sin_family inet_pton(AF_INET, // inet_addr() adresse.sin_port = adresse; = AF_INET; "172.29.2.43", &(adresse.sin_addr)); est deprecated... htons(9090); // Integer -> uint16_t Fonctions de conversion / constantes utiles char ip[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &(adresse.sin_addr), ip, INET_ADDRSTRLEN); adr_serveur.sin_addr.s_addr = htonl(INADDR_ANY); // Pour utiliser n'importe quelle adresse locale Remarque : fonctions dédiées aux IPv4 13 Sockets en C mode non connecté Fonctionnement de base Serveur socket() bind() recvfrom() bloquant Client socket() bind() sendto() recvfrom() sendto() close() bloquant close() 15 Réception d'un message Retourne -1 si erreur Le socket int recvfrom( int s, Le buffer pour stocker le message void *buf, 0 dans 99% des cas unsigned flags, Adresse de l'émetteur const struct sockaddr *from longueur maximale de l’adresse int len, Le taille maximale du buffer int *fromlen); 16 Envoi d'un message Retourne -1 si erreur int sendto( Le message Le socket int s, const void *msg, int len, Longueur du message en octets 0 dans 99% des cas unsigned flags, Adresse du destinataire const struct sockaddr *to Longueur de l’adresse int tolen); 17 Exemple de serveur #include #include #include #include #include #include #include #include #include #include <stdio.h> <unistd.h> <stdlib.h> <errno.h> <string.h> <time.h> <sys/types.h> <sys/socket.h> <netinet/in.h> <arpa/inet.h> static void erreur(const char *message) { fputs(strerror(errno), stderr); fputs(": ", stderr); fputs(message, stderr); fputc('\n', stderr); exit(1); } int main(int argc,char **argv) { char *IPServeur=NULL, nom[512], message[512], ipClient[INET_ADDRSTRLEN]; int portServeur, socketServeur, longueur, nbOctets; struct sockaddr_in adresseServeur, adresseClient; // Récupération des paramètres if ( argc>=3 ) { IPServeur = argv[1]; portServeur = atoi(argv[2]); }else if( argc>=2 ){ IPServeur = "127.0.0.1"; }else { IPServeur = "127.0.0.1"; portServeur = 1024; } // Construction de l'adresse memset(&adresseServeur, 0, sizeof(adresseServeur)); adresseServeur.sin_family = AF_INET; adresseServeur.sin_port = htons(portServeur); inet_pton(AF_INET, IPServeur, &(adresseServeur.sin_addr)); if(adresseServeur.sin_addr.s_addr==INADDR_NONE) erreur("mauvaise addresse"); // Création du Socket socketServeur = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if( socketServeur==-1 ) erreur("socket"); 18 Exemple de serveur // Bind if( bind(socketServeur, (struct sockaddr *)&adresseServeur, sizeof(adresseServeur))==-1 ) erreur("bind()"); // Ecouter le Socket et traiter les requêtes longueur = sizeof(adresseClient); nbOctets = recvfrom(socketServeur, nom, sizeof(nom), 0, (struct sockaddr *)&adresseClient, &longueur); if(nbOctets==-1) { erreur("rcvfrom()"); }else { nom[nbOctets]='\0'; inet_ntop(AF_INET, &(adresseClient.sin_addr), ipClient, INET_ADDRSTRLEN); printf("(%s:%u) : '%s'\n", ipClient, (unsigned)ntohs(adresseClient.sin_port), nom); strcpy(message, "Hello "); strcat(message, nom); strcat(message, " !"); if( sendto(socketServeur, message, strlen(message), 0, (struct sockaddr *)&adresseClient, longueur)==-1 ) erreur("sendto()"); } close(socketServeur); return 1; } 19 Exemple de client // Envoi du nom strcpy(nom, argv[3]); // 3eme argument : nom envoye = sendto(s, nom, strlen(nom), 0 , (struct sockaddr *)&adr_serveur, sizeof(adr_serveur)); if( envoye < 0 ) erreur("sendto()"); int main(int argc,char **argv) { int s, sb, envoye, recu, l; struct sockaddr_in adr_serveur, struct sockaddr_in adr_client, adr; char nom[512], message[512], char ip[INET_ADDRSTRLEN]; // Création de l'adresse adr_serveur.sin_family = AF_INET; inet_pton(AF_INET, argv[1], &(adr_serveur.sin_addr)); // 1er argument : IP du serveur adr_serveur.sin_port = htons(atoi(argv[2])); // 2nd argument : port du serveur // Réception de la réponse l = sizeof(adr); recu = recvfrom(s, message, sizeof(message), 0, (struct sockaddr *)&adr, &l); if( recu < 0 ) erreur("recvfrom()"); message[recu] = 0; inet_ntop(AF_INET, &(adr.sin_addr), ip, INET_ADDRSTRLEN); printf("Message recu (par %s:%u) : '%s'\n", ip,(unsigned)ntohs(adr.sin_port), message); if(adr_serveur.sin_addr.s_addr==INADDR_NONE) erreur("mauvaise addresse"); // Création du Socket s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if ( s == -1 ) erreur("socket()"); close(s); putchar('\n'); return 0; } 20 Sockets en C mode connecté Fonctionnement de base Serveur Client socket() bind() listen() socket() bind() accept() bloquant connect() read() / write() read() / write() close() close() 22 Les fonctions listen() et accept() int listen( int socketid, int backlog) Identifiant de socket Longueur maximale de la file d ’attente 0 si Ok -1 sinon int accept( int socketid, struct sockaddr* addr, int* addrlen) 0 si Ok -1 sinon Longueur de l’adresse Identifiant de socket Adresse du client 23 La connextion int connect( int socketid, Identifiant de socket valeur retournée par socket() Retourne -1 si erreur struct sockaddr *addr, adresse du serveur int addrlen) longueur en octets de l ’adresse 24 Exemple de serveur #include #include #include #include #include #include #include #include #include #include <stdio.h> <unistd.h> <stdlib.h> <errno.h> <string.h> <time.h> <sys/types.h> <sys/socket.h> <netinet/in.h> <arpa/inet.h> // Récupération des paramètres if ( argc>=3 ) { IPServeur = argv[1]; portServeur = atoi(argv[2]); }else if( argc>=2 ){ IPServeur = "127.0.0.1"; }else { IPServeur = "127.0.0.1"; portServeur = 1024; } static void erreur(const char *message) { fputs(strerror(errno), stderr); fputs(": ", stderr); fputs(message, stderr); fputc('\n', stderr); exit(1); } // Construction de l'adresse memset(&adresseServeur, 0, sizeof(adresseServeur)); adresseServeur.sin_family = AF_INET; adresseServeur.sin_port = htons(portServeur); inet_pton(AF_INET, IPServeur, &(adresseServeur.sin_addr)); int main(int argc,char **argv) { char *IPServeur=NULL, nom[512], message[512], ipClient[INET_ADDRSTRLEN]; int portServeur, socketServeur, longueur, socketClient, recu; struct sockaddr_in adresseServeur, adresseClient; if(adresseServeur.sin_addr.s_addr==INADDR_NONE) erreur("mauvaise addresse"); // Création du Socket socketServeur = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if( socketServeur==-1 ) erreur("socket"); 25 Exemple de serveur // Bind if( bind(socketServeur, (struct sockaddr *)&adresseServeur, sizeof(adresseServeur))==-1 ) erreur("bind()"); // Ecoute du Socket if( listen(socketServeur, 10)==-1) erreur("listen()"); // Traitement de la requête longueur = sizeof(adresseClient); socketClient = accept(socketServeur, (struct sockaddr *)&adresseClient, &longueur); if(socketClient==-1) { erreur("accept()"); }else { recu = read(socketClient, &nom, sizeof(nom)-1); if( recu==-1) erreur("read()"); nom[recu-1]='\0'; inet_ntop(AF_INET, &(adresseClient.sin_addr), ipClient, INET_ADDRSTRLEN); printf("(%s:%u) : '%s'\n", ipClient, (unsigned)ntohs(adresseClient.sin_port), nom); strcpy(message, "Salut "); strcat(message, nom); strcat(message, " !\n"); if( write(socketClient, message, strlen(message))==-1 ) erreur("write()"); } close(socketClient); close(socketServeur); return 1; } 26 Exemple de client // Connection SocketServeur = connect(socketClient, (struct sockaddr *)&adr_serveur, sizeof(adr_serveur)); if( socketServeur==-1 ) erreur("connect()"); int main(int argc,char **argv) { int socketClient, socketServeur, recu; struct sockaddr_in adr_serveur, adr_client, adr; char nom[512], message[512], ip[INET_ADDRSTRLEN]; // Envoi de la requête strcpy(nom, argv[3]); // 3eme argument : nom strcat(nom, "\n"); if( write(socketClient, nom, strlen(nom))==-1 ) erreur("write()"); // Création de l'adresse adr_serveur.sin_family = AF_INET; inet_pton(AF_INET, argv[1], &(adr_serveur.sin_addr)); // 1er argument : IP du serveur adr_serveur.sin_port = htons(atoi(argv[2])); // 2nd argument : port du serveur if(adr_serveur.sin_addr.s_addr==INADDR_NONE) erreur("mauvaise addresse"); // Réception de la réponse recu = read(socketClient, &message, sizeof(message)-1); if( recu==-1 ) erreur("read()"); message[recu-1] = '\0'; // Création du Socket socketClient = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if ( socketClient == -1 ) erreur("socket()"); inet_ntop(AF_INET, &(adr.sin_addr), ip, INET_ADDRSTRLEN); printf("(%s:%u) : '%s'\n", ip, (unsigned)ntohs(adr.sin_port), message); close(socketServeur); close(socketClient); return 0; } 27 Sockets en Java Le package java.net java.lang.Object java.net InetAddress Inet4Address Inet6Address SocketAddress DatagramPacket DatagramSocket InetSocketAddress Socket ServerSocket 29 Classe InetAdress ● Représente les adresses IP ● Encapsule l'accès au serveur de noms DNS ● Pas de création d'instance mais : public static InetAddress getLocalHost() throws UnknownHostException public static InetAddress getByName(String host) throws UnknownHostException public static InetAddress[] getAllByName(String host) throws UnknownHostException 30 Classe Socket ● ● Sockets de flux (client et serveur) Méthodes de base : public Socket(String host, int port) throws UnknownHostException, IOException public Socket(InetAddress address, int port) throws IOException public InetAddress getInetAddress() // adresse IP distante public InetAddress getLocalAddress() // adresse IP locale public int getPort() // port distant public int getLocalPort() // port local public InputStream getInputStream() throws IOException public OutputStream getOutputStream() throws IOException void close() 31 Sockets en Java mode non connecté 32 Classe DatagramSocket ● Communication en mode non connecté ● Client/serveur via une interface par socket ● Méthodes de base : public DatagramSocket() throws SocketException public DatagramSocket(int port) throws SocketException public DatagramSocket(int port, InetAddress addr) throws SocketException void close() InetAddress getInetAddress() int getPort() InetAddress getLocalAddress() int getLocalPort() public void send(DatagramPacket p) throws IOException public void receive(DatagramPacket p) throws IOException 33 Classe DatagramPacket ● Méthodes de base : DatagramPacket(byte[] buf, int length) DatagramPacket(byte[] buf, int length, InetAddress address, int port) InetAddress getAddress() byte[] getData() int getLength() int getPort() void setAddress(InetAddress iaddr) void setData(byte[] buf) void setLength(int length) void setPort(int iport) 34 Fonctionnement de base Serveur Client s = new DatagramSocket(...) s = new DatagramSocket(...) r = new DatagramPacket(...) e = new DatagramPacket(...) r = new DatagramPacket(...) s.receive(r) bloquant e = new DatagramPacket(...) s.send(e) s.receive(r) s.send(e) bloquant s.close() s.close() 35 Exemple de serveur import java.io.*; import java.util.*; import java.net.*; // Réponse adresseClient = reception.getAddress(); portClient = reception.getPort(); nom = new String(reception.getData(), 0, reception.getLength()); System.out.println("Message de (" + adresseClient + ":" + portClient + ") => " + nom); message = "Salut " + nom + " !"; reponse = message.getBytes(); envoi = new DatagramPacket(reponse, reponse.length, adresseClient, portClient); socket.send(envoi); public class Serveur { public static void main(String[] args) throws Exception { InetAddress adresseClient; int portClient; DatagramSocket socket; byte[] requete = new byte[100], reponse; DatagramPacket reception, envoi; String nom, message; if(args.length != 2) { System.out.println("2 arguments : IP Port)"); } else { // Création du Socket socket = new DatagramSocket(Integer.parseInt(args[1]), InetAddress.getByName(args[0])); //Fermeture du Socket socket.close(); } } } // Création du DatagramPacket // et réception d'une requête reception = new DatagramPacket(requete, requete.length); socket.receive(reception); 36 Exemple de client import java.io.*; import java.util.*; import java.net.*; public class Client { public static void main(String[] args) throws Exception { InetAddress adresse = InetAddress.getByName(args[0]); int portUDP = Integer.parseInt(args[1]); byte[] requete = args[2].getBytes(), reponse = new byte[100], test; // Création du Socket DatagramSocket socket = new DatagramSocket(); // Création des DatagramPacket d'envoi et de réception DatagramPacket envoi = new DatagramPacket(requete, requete.length, adresse, portUDP), reception = new DatagramPacket(reponse, reponse.length); // Requête : envoi puis réception socket.send(envoi); socket.receive(reception); String texte = new String(reception.getData(), 0, reception.getLength()); System.out.println(texte); // Fermeture du Socket socket.close(); } } 37 Sockets en Java mode connecté 38 Classe ServerSocket ● Communication en mode connecté ● Client/serveur via une interface par socket ● Constructeur : public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException ● Acceptation d'une connexion client (bloquant) public Socket accept() throws IOException 39 Fonctionnement de base Serveur Client se = new ServerSocket(...) sc = se.accept() bloquant s = new Socket(...) is = sc.getInputStream() os = sc.getOutputStream() is = s.getInputStream() os = s.getOutputStream() lectures/écriture lectures/écriture s.close() s.close() 40 Exemple de serveur import java.io.*; import java.util.*; import java.net.*; // Lecture d'une requête socketInputStream = new BufferedReader( new InputStreamReader( socketClient.getInputStream())); nom = socketInputStream.readLine(); System.out.println("Message de (" + socketClient.getInetAddress() + ":" + socketClient.getPort() + ") => " + nom); public class Serveur { public static void main(String[] args) throws Exception { ServerSocket socketEcoute; Socket socketClient; PrintStream socketOutputStream; BufferedReader socketInputStream; String nom; if(args.length != 2) { System.out.println("2 arguments : IP Port)"); } else { // Création du Socket et mise en attente socketEcoute = new ServerSocket(Integer.parseInt(args[1]), 10, InetAddress.getByName(args[0])); socketClient = socketEcoute.accept(); // Écriture de la réponse socketOutputStream = new PrintStream( socketClient.getOutputStream()); socketOutputStream.print("Salut " + nom + " !\n"); // Fermeture des Sockets socketClient.close(); socketEcoute.close(); } } } 41 Exemple de client import java.io.*; import java.util.*; import java.net.*; public class Client { public static void main(String[] args) throws Exception { Socket s; PrintStream socketOutputStream; BufferedReader socketInputStream; int erreur; if(args.length != 3) { System.out.println("4 arguments : IP Port Nom)"); } else { // Création du Socket s = new Socket(args[0], Integer.parseInt(args[1])); // Écriture de la requête socketOutputStream = new PrintStream(s.getOutputStream()); socketOutputStream.print(args[2] + "\n"); // Récupération de la réponse socketInputStream = new BufferedReader(new InputStreamReader(s.getInputStream())); System.out.println(socketInputStream.readLine()); // Fermeture du Socket s.close(); } } } 42 Références ● [1] http://deptinfo.unice.fr/~dalle/wiki/uploads/Enseigne ments/7-SYS-L2.pdf 43