Chapitre IX : Introduction ` a la programmation r´ eseau
Eric.Leclercq@u-bourgogne.fr
D´ epartement IEM
http://ufrsciencestech.u-bourgogne.fr http://ludique.u-bourgogne.fr/~leclercq
11 mai 2006
1 La communication client serveur TCP/IP Principes de base
2 Les sockets en Java L’API r´ eseau de Java Les types de socket La r´ esolution de nom
Traitement des clients multiples Datagrammes UDP
3 Sockets avanc´ es Options des sockets S´ erialisation
S´ erialisation
Notion de socket
D´ efinition :
Apparu ` a l’origine dans les syst` emes UNIX, un socket est une abstraction logicielle qui r´ ealise une interface logicielle avec les services r´ eseau du syst` eme d’exploitation, grˆ ace ` a laquelle un programme peut communiquer de mani` ere uniforme avec d’autre programme situ´ es sur des machines diff´ erentes.
Ainsi les socket permettent l’´ echange de donn´ ees entre 2 processus sur deux machines distinctes ;
Chaque machine (programme) cr´ ee un socket ; Chaque socket est associ´ e ` a un port (diff´ erent) ; Les deux socket devront ´ eventuellement ˆ etre connect´ es explicitement.
Les programmes lisent et ´ ecrivent dans les sockets.
Notion de port
Un service r´ eseau TCP/IP est accessible par un port ce qui permet d’aiguiller les donn´ ees vers le processus dans le SE.
Un port est identifi´ e par un entier (16 bits).
Les ports num´ erot´ es de 0 ` a 511 sont qualifi´ e well known ports : ils donnent acc` es aux services standard (transfert de fichiers FTP port 21, terminal Telnet port 23, courrier SMTP port 25, serveur web port 80)
De 512 ` a 1023, on trouve les services Unix.
Au del` a, (1024 ...) ce sont les ports utilisateurs disponibles pour un service applicatif quelconque.
Un service est souvent connu par un nom : la correspondance entre nom et num´ ero de port est donn´ ee par le fichier
/etc/services
API Java
L’API (Application Programming Interface) sockets est une biblioth` eque de classes de communication pour TCP/IP (java.net). Elle offre deux modes de communication :
le mode connect´ e correspond au protocole TCP : le protocole ´ etablit une connexion virtuelle
se charge alors de maintenir l’int´ egrit´ e de la communication g´ ere les erreurs de transmission
Le mode non connect´ e correspond au protocole UDP : l’envoi est fait au mieux (best effort). C’est ` a l’application de
maintenir la qualit´ e de la transmission.
Les classes socket
Java propose 4 types de classes : Pour UDP :
DatagramSocket() pour un client
DatagramSocket(ServerPort) pour un serveur Pour TCP :
Socket(ServerName,ServerPort) pour un client
ServerSocket(ServerPort) pour un serveur
Les sockets TCP doivent ˆ etre associ´ e ` a des flux
Classe Socket
Constructeur : Socket (String host, int port) cr´ eation du socket vers le port et la machine hˆ ote sp´ ecifi´ es
M´ ethodes :
close() : ferme le socket ;
OutputStream getOutputStream() : renvoie un flux de sortie pour le socket ;
IntputStream getIutputStream() : renvoie un flux de
d’entr´ ee pour le socket.
Classe ServerSocket
Constructeur : ServerSocket (int port) creation du socket serveur sur le port sp´ ecifi´ e
M´ ethodes :
close() : ferme le socket ;
OutputStream getOutputStream() : renvoie un flux de sortie pour le socket ;
IntputStream getIutputStream() : renvoie un flux de d’entr´ ee pour le socket ;
Socket accept() : ´ ecoute si une connexion est demand´ ee
pour ce socket et l’accepte.
La r´ esolution de nom
La mise en œuvre de la r´ esolution des noms se fait ` a travers un service DNS ou un fichier local (/etc/hosts).
Ce service est accessible via la classe InetAddress.
Cette classe repr´ esente les adresses IP et un ensemble de m´ ethodes pour les manipuler.
les applications doivent utiliser les m´ ethodes getLocalHost, getByName, ou getAllByName pour construire une nouvelle instance de InetAddress
public class InetAddress implements Serializable InetAddress getByName(String host) : construit un nouvel objet InetAddress ` a partir d’un nom textuel sous forme symbolique ou sous forme num´ erique
String getHostName() : obtient le nom complet correspondant ` a l’adresse IP
String getHostAddress() :obtient l’adresse IP sous forme num´ erique
byte[] getAddress() :obtient l’adresse IP sous forme d’un
tableau d’octets
Exemple
1 i m p o r t j a v a . net .*;
2 p u b l i c c l a s s W h o A m I {
3 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) t h r o w s E x c e p t i o n { 4 if( a r g s . l e n g t h != 1) {
5 S y s t e m . err . p r i n t l n ( " U s a g e : W h o A m I M a c h i n e N a m e " ) ; 6 S y s t e m . e x i t (1) ;
7 }
8 I n e t A d d r e s s a = I n e t A d d r e s s . g e t B y N a m e ( a r g s [ 0 ] ) ; 9 S y s t e m . out . p r i n t l n ( a ) ;
10 }
Clients multiples
1 p u b l i c c l a s s S e r v e u r C o n c u r r e n t { 2 f i n a l s t a t i c int p o r t = 1 3 1 4 ;
3 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) 4 t h r o w s I O E x c e p t i o n {
5 S e r v e r S o c k e t s e r v e u r = new S e r v e r S o c k e t ( p o r t ) ; 6 w h i l e (t r u e) {
7 C o n n e x i o n c o n n e x i o n = new C o n n e x i o n ( s e r v e u r . a c c e p t () ) ; 8 c o n n e x i o n . s t a r t () ;}
9 }
10 }
11 c l a s s C o n n e x i o n e x t e n d s T h r e a d { 12 S o c k e t c o n n e x i o n ;
13 C o n n e x i o n ( S o c k e t s ) {
14 c o n n e x i o n = s ;}
15 p u b l i c v o i d run () { 16 S t r i n g r e q u e t e ;
17 try { P r i n t W r i t e r out =
18 new P r i n t W r i t e r ( c o n n e x i o n . g e t O u t p u t S t r e a m () ) ;
19 B u f f e r e d R e a d e r in =new B u f f e r e d R e a d e r (new I n p u t S t r e a m R e a d e r ( 20 c o n n e x i o n . g e t I n p u t S t r e a m () ) ) ;
21 out . p r i n t l n ( " = > " ) ;
22 w h i l e (!( r e q u e t e = in . r e a d L i n e () ) . e q u a l s ( " FIN " ) ) {
23 out . p r i n t l n ( r e q u e t e + " d e p u i s " + c o n n e x i o n . g e t I n e t A d d r e s s () + " : " + c o n n e x i o n . g e t P o r t () ) ;
24 out . f l u s h () ;
25 }
26 c o n n e x i o n . c l o s e () ;
27 }
28 c a t c h ( I O E x c e p t i o n e ) { S y s t e m . err . p r i n t l n ( e ) ;}
29 }
30 }
Datagrammes
le protocole UDP est beaucoup plus simple que TCP : ne permet pas de reconstituer l’ordre d’envoi des messages ; donc plus efficace en bande passante ;
mais moins fiable puisqu’il n’est pas dot´ e d’accus´ e de r´ eception (automatique)
les donn´ ees sont plac´ ees dans un datagramme UDP, muni d’un en-tˆ ete comportant les num´ eros de port d’origine et de destination, la taille du datagramme et une somme de contrˆ ole ;
ce datagramme est lui-mˆ eme plac´ e dans un datagramme IP (ou paquet IP), muni d’un en-tˆ ete comportant entre autre les adresses IP d’´ emission et de r´ eception ;
la taille des donn´ ees est limit´ ee ` a 65 507 octets ;
impl´ ement´ es en Java par la classe DatagramPacket (les
donn´ ees sont contenues dans un tableau d’octet).
Datagrammes
Cˆ ot´ e Client :
1 S t r i n g s = " D A T A D A T A D T A T A " ; 2 b y t e[] d o n n e e s = s . g e t B y t e s () ;
3 I n e t A d d r e s s a d r e s s e = I n e t A d d r e s s . g e t B y N a m e ( " le nom de l ’ h o t e " ) ; 4 int p o r t = 5 5 5 5 ;
5 D a t a g r a m P a c k e t p a q u e t =
6 new D a t a g r a m P a c k e t ( donnees , d o n n e e s . length , adresse , p o r t ) ;
En r´ eception cˆ ot´ e serveur : il faut construire un datagramme c` ad tableau d’octets qui recevra les donn´ ees
1 b y t e[] d o n n e e s = new b y t e[ 4 0 0 0 ] ; ; 2 D a t a g r a m P a c k e t d =
3 new D a t a g r a m P a c k e t ( donnees , d o n n e e s . l e n g t h ) ;
Socket UDP
Les datagrammes sont ´ emis et re¸ cus par l’interm´ ediaire d’un objet de la classe DatagramSocket
Cˆ ot´ e client : on utilise un port pour construire le DatagramSocket, puis la m´ ethode send
1 D a t a g r a m S o c k e t c l i e n t = new D a t a g r a m S o c k e t () ; 2 c l i e n t . s e n d ( p a q u e t ) ;
Cˆ ot´ e serveur : le port doit ˆ etre pass´ e en argument au
constructeur DatagramSocket(int), et la m´ ethode receive remplit le tableau d’octets avec les donn´ ees du paquet re¸ cu
1 D a t a g r a m S o c k e t s e r v e u r = new D a t a g r a m S o c k e t ( p o r t ) ; 2 s e r v e u r . r e c e i v e ( p a q u e t ) ;
Serveur ECHO UDP
1 i m p o r t j a v a . io .*;
2 i m p o r t j a v a . net .*;
3 c l a s s S e r v e u r E c h o U D P {
4 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) 5 t h r o w s U n k n o w n H o s t E x c e p t i o n , I O E x c e p t i o n { 6 f i n a l int p o r t = 8 0 8 0 ;
7 D a t a g r a m P a c k e t p a q u e t R e q u e t e , p a q u e t R e p o n s e ; 8 D a t a g r a m S o c k e t s e r v e u r = new D a t a g r a m S o c k e t ( p o r t ) ; 9 b y t e[] d o n n e e s R e q u e t e = new b y t e[ 4 0 0 0 ] ;
10 w h i l e (t r u e) {
11 p a q u e t R e q u e t e = new D a t a g r a m P a c k e t ( d o n n e e s R e q u e t e , d o n n e e s R e q u e t e . l e n g t h ) ; 12 s e r v e u r . r e c e i v e ( p a q u e t R e q u e t e ) ;
13 p a q u e t R e p o n s e =
14 new D a t a g r a m P a c k e t ( p a q u e t R e q u e t e . g e t D a t a () , 15 p a q u e t R e q u e t e . g e t L e n g t h () ,
16 p a q u e t R e q u e t e . g e t A d d r e s s () , 17 p a q u e t R e q u e t e . g e t P o r t () ) ; 18 s e r v e u r . s e n d ( p a q u e t R e p o n s e ) ;
19 }
20 }
21 }
Client ECHO UDP
1 c l a s s C l i e n t E c h o U D P {
2 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) 3 t h r o w s U n k n o w n H o s t E x c e p t i o n , I O E x c e p t i o n { 4 S t r i n g n o m H o t e = " l o c a l h o s t " ;
5 I n e t A d d r e s s a d r e s s e = I n e t A d d r e s s . g e t B y N a m e ( n o m H o t e ) ; 6 f i n a l int p o r t = 8 0 8 0 ;
7 S t r i n g requete , r e p o n s e ;
8 D a t a g r a m P a c k e t p a q u e t R e q u e t e , p a q u e t R e p o n s e ; 9 D a t a g r a m S o c k e t c l i e n t = new D a t a g r a m S o c k e t () ;
10 B u f f e r e d R e a d e r e n t r e e = new B u f f e r e d R e a d e r (new I n p u t S t r e a m R e a d e r ( S y s t e m . in ) ) ;
11 b y t e[] d o n n e e s R e p o n s e = new b y t e[ 4 0 0 0 ] ;
12 w h i l e (!( r e q u e t e = e n t r e e . r e a d L i n e () ) . e q u a l s ( " END " ) ) { 13 d o n n e e s R e q u e t e = r e q u e t e . g e t B y t e s () ;
14 p a q u e t R e q u e t e =new D a t a g r a m P a c k e t ( d o n n e e s R e q u e t e , 15 d o n n e e s R e q u e t e . length , adresse , p o r t ) ;
16 p a q u e t R e p o n s e = new D a t a g r a m P a c k e t ( d o n n e e s R e p o n s e , d o n n e e s R e p o n s e . l e n g t h ) ; 17 c l i e n t . s e n d ( p a q u e t R e q u e t e ) ;
18 c l i e n t . r e c e i v e ( p a q u e t R e p o n s e ) ;
19 r e p o n s e = new S t r i n g ( p a q u e t R e p o n s e . g e t D a t a () ) ;
20 S y s t e m . out . p r i n t l n ( p a q u e t R e p o n s e . g e t A d d r e s s () + " : " + r e p o n s e ) ;
21 }
22 c l i e n t . c l o s e () ;
23 }
24 }
Options des sockets
Il est possible de d´ efinir le comportement des sockets avec les options via une m´ ethode set suivie du nom de l’option (grand nombre) :
SO TIMEOUT (minuterie sur les m´ ethodes bloquantes) : ` a tester avec Interrupted Exception
TCP NODELAY : envoi de paquet tr` es rapidement (attention aux petits paquets) - Algorithme de Nagle
SO LINGER : gestion des donn´ ees non transmises
TCP KEEPALIVE : gestion de l’inactivit´ e
Protocoles d’objets s´ erialis´ es
D´ efinir les classes d’objets s´ erialisables :
1 // c e t t e d ´e f i n i t i o n d o i t ^e t r e a c e s s i b l e au c l i e n t et au s e r v e u r 2 c l a s s O b j e t i m p l e m e n t s S e r i a l i z a b l e {
3 p u b l i c S t r i n g nom ; 4 p u b l i c O b j e t ( S t r i n g n ) {
5 nom = new S t r i n g ( n ) ;
6 }
7 p u b l i c S t r i n g t o S t r i n g () { 8 r e t u r n " O b j e t : nom " ;
9 }
10 }
Cˆ ot´ e client :
1 p u b l i c c l a s s C l i e n t {
2 s t a t i c f i n a l int p o r t = 8 0 8 0 ;
3 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) t h r o w s E x c e p t i o n { 4 S o c k e t s o c k e t = new S o c k e t ( a r g s [0] , p o r t ) ;
5 S y s t e m . out . p r i n t l n ( " S O C K E T = " + s o c k e t ) ;
6 O b j e c t O u t p u t S t r e a m oss = new O b j e c t O u t p u t S t r e a m ( s o c k e t . g e t O u t p u t S t r e a m () ) ;
7 oss . w r i t e O b j e c t (new O b j e t ( " mon o b j e t " ) ) ; 8 S y s t e m . out . p r i n t l n ( " END " ) ;
9 // a t t e n t i o n aux c o m m a n d e s de t y p e p r o t o c o l e 10 oss . w r i t e O b j e c t ( " END " ) ;
11 oss . c l o s e () ;
12 s o c k e t . c l o s e () ;
13 }
14 }
Protocoles d’objets s´ erialis´ es
Cˆ ot´ e serveur :
1 p u b l i c c l a s s S e r v e u r {
2 s t a t i c f i n a l int p o r t = 8 0 8 0 ;
3 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) t h r o w s E x c e p t i o n { 4 S e r v e r S o c k e t s = new S e r v e r S o c k e t ( p o r t ) ;
5 S o c k e t soc = s . a c c e p t () ;
6 O b j e c t I n p u t S t r e a m ois = new O b j e c t I n p u t S t r e a m ( 7 soc . g e t I n p u t S t r e a m () ) ;
8 w h i l e (t r u e) {
9 O b j e c t o = ois . r e a d O b j e c t () ;
10 if ( o . e q u a l s ( " END " ) ) b r e a k;
11 S y s t e m . out . p r i n t l n ( o ) ; // t r a c e l o c a l e
12 }
13 ois . c l o s e () ;
14 soc . c l o s e () ;
15 }
16 }