Programmation Événementielle Et Réseau: IUT Béthune DUT2 Réseaux & Télécommunications
Programmation Événementielle Et Réseau: IUT Béthune DUT2 Réseaux & Télécommunications
Programmation Événementielle Et Réseau: IUT Béthune DUT2 Réseaux & Télécommunications
IUT Béthune
DUT2 Réseaux & Télécommunications
Daniel Porumbel
1/48
1 Sockets : Communication entre machines
2/48
1 Sockets : Communication entre machines
Définition socket et rappels pile TCP/IP
Fonctionnement des sockets
Les sockets en pratique
3/48
A quoi servent les sockets ?
Applications client/serveur
Serveurs et clients web
Transfert de fichiers
Jeux en réseau
Console à distance
Groupes de discussions
4/48
Rappels : pile TCP/IP et couche transport
1 Couche Application
(Firefox, MSN,
FTP)
2 Couche Transport
(TCP/UDP)
3 Couche Réseaux
(routage)
4 Couche Liaison
5/48
La Couche Application
8/48
Rappel Couche Transport
9/48
Couche Transport et Couche Application
9/48
Exemple de communication entre sockets
10/48
Plusieurs Types de Sockets
11/48
Plusieurs Types de Sockets
11/48
Sockets en ligne de commande
L’utilitaire netcat permet de manipuler tout type de sockets
Attention : installer le paquet netcat-traditional et pas
openbsd
En raison de sa polyvalence, netcat est aussi appelé le
“couteau suisse du TCP/IP”
12/48
Sockets en ligne de commande
L’utilitaire netcat permet de manipuler tout type de sockets
Attention : installer le paquet netcat-traditional et pas
openbsd
En raison de sa polyvalence, netcat est aussi appelé le
“couteau suisse du TCP/IP”
mode client : netcat IP PORT
mode serveur : netcat -l -p PORT
Par défaut, netcat utilise des sockets STREAM (TCP) :
l’option "-u" permet de passer en mode DGRAM (UDP).
1 n e t c a t i u t − r t 22 # connexion ssh
2 n e t c a t − l −p 8080 # e c o u t e r l e p o r t 8080
3 n e t c a t −u − l −p 8080 # e c o u t e r l e p o r t 8080
UDP
4 n e t c a t −u −b 1 72 .3 1.2 5. 25 5 3128 # envoie
message UDP en d i f f u s i o n
12/48
Sockets en Ruby : client TCP
13/48
Sockets en Ruby : serveur TCP
La classe TCPServer permet de construire un serveur (via
TCPServer.open)
Ce serveur doit “accepter” un client qui se connecte
Résultat : un objet session de connexion socket serveur ↔
socket client
L’objet résultant permet de recevoir des données (via gets)
ou bien d’envoyer (puts)
1 # ! / u s r / b i n / ruby
2 r e q u i r e ’ socket ’
3 s e r v e r = TCPServer . open ( 1 2 3 4 )
4 s e s s i o n = s e r v e r . accept ( )
5 puts ( session . gets ( ) )
6 s e s s i o n . p u t s ’ Bien recu ’
7 session . close ( )
14/48
Sockets en Ruby : client UDP
Le client UDP est différent du client TCP. Voici quelques
opérations
Création socket local via UDPSocket.new
“Connexion” à une socket UDP distant
pas une vraie connexion comme pour TCP
cette opération fait le nécessaire pour pouvoir envoyer/rece-
voir des données
Le port local est disponible via l’attribut addr
Envoi et réception de données via send()/recvfrom()
1 # ! / u s r / b i n / ruby
2 r e q u i r e ’ socket ’
3 maSocketUdp = UDPSocket . new
4 maSocketUdp . connect ( " 1 2 7 . 0 . 0 . 1 " , 1234)
5 p u t s maSocketUdp . addr [ 1 ]
6 maSocketUdp . send ( " aaa " , 0 )
7 p u t s maSocketUdp . r e c v f r o m ( 1 0 0 , 0 )
8 maSocketUdp . c l o s e
15/48
Sockets en Ruby : serveur UDP
On utilise toujours un objet UDPSocket : la méthode bind()
associe la socket UDP à un port local
IP local : 0.0,0,0, port à votre choix
Réception de messages : recvfrom (pas de gets() comme
pour TCP) → un tableau à deux positions :
pos 0 Le message : une chaîne de caractères
pos 1 Informations sur l’émetteur : tableau à 4 positions :[0] type
adresse, [1] port, [2] nom, [3] ip émetteur
1 r e q u i r e ’ socket ’
2 sockUdp = UDPSocket . open ( )
3 sockUdp . b i n d ( " 0 . 0 . 0 . 0 " , 1234)
4 f o r i i n 1 . . 5 do
5 msg = sockUDP . r e c v f r o m ( 1 0 0 , 0 )
6 p u t s " Recu msg de " +msg [ 1 ] [ 3 ] + " : " +msg [ 0 ]
7 end
8 sockUdp . c l o s e ( )
16/48
Sockets en Ruby : UDP en diffusion
Pour pouvoir envoyer des paquets en diffusion, l’objet
UDPSocket doit activer l’option Socket::SO_BROADCAST
Méthode utilisée : setsockopt(niveau,option,valeur)
niveau=Socket::SOL_SOCKET – modifications au niveau
de la socket (et non pas SOL_TCP, SOL_UDP)
option=Socket::SO_BROADCAST et valeur=true
L’adresse de diffusion est disponible via ifconfig
1 r e q u i r e ’ socket ’
2 sockUdpBCast = UDPSocket . new
3 sockUdpBCast . s e t s o c k o p t ( Socket : : SOL_SOCKET,
Socket : : SO_BROADCAST, t r u e )
4 sockUdpBCast . connect ( " 172 .3 1. 25. 25 5 " , 1234)
5 sockUdpBCast . send ( " S a l u t l e monde " , 0 )
6 sockUdpBCast . c l o s e ( )
17/48
Méthodes importantes (bibliothèque socket)
18/48
Résumé des sockets
Sockets TCP
client Exemple : session=TCPSocket.open(...)
serveur Deux opérations : open et accept
serv=TCPServer.open(...)
session=serv.accept()
utilisation session.puts(...) et session.gets(...)
Sockets UDP
client Création objet et connexion à distance (pas une vraie connexion comme pour
TCP)
sockUDP=UDPSocket.new
sockUDP.connect(...)
serveur Deux opérations : open et bind
sockUDP=UDPSocket.open()
sockUDP.bind(...)
utilisation sockUdp.send(...) ou sockUdp.recvfrom
19/48
1 Sockets : Communication entre machines
20/48
Le flux du programme : paradigme classique
Paradigme séquentiel
Un programme = une séquence d’instructions en série :
1 a=b
2 c=a*a-a
3 puts(Math.log(c))
4 .....
21/48
Le flux du programme : paradigme classique
Paradigme séquentiel
Un programme = une séquence d’instructions en série :
1 a=b
2 c=a*a-a
3 puts(Math.log(c))
4 .....
1 toute erreur peut provoquer un crash du programme
21/48
Le flux du programme : paradigme classique
Paradigme séquentiel
Un programme = une séquence d’instructions en série :
1 a=b
2 c=a*a-a
3 puts(Math.log(c))
4 .....
1 toute erreur peut provoquer un crash du programme
2 pas possible de gérer plusieurs clients au même temps
3 l’interaction avec l’utilisateur est programmée en avance
l’utilisateur intervient uniquement lorsqu’on arrive à une ins-
truction comme gets()
21/48
Le flux du programme : paradigme classique
Paradigme séquentiel
Un programme = une séquence d’instructions en série :
1 a=b
2 c=a*a-a
3 puts(Math.log(c))
4 .....
1 toute erreur peut provoquer un crash du programme
2 pas possible de gérer plusieurs clients au même temps
3 l’interaction avec l’utilisateur est programmée en avance
l’utilisateur intervient uniquement lorsqu’on arrive à une ins-
truction comme gets()
Paradigme non-séquentiel
La programmation graphique/réseau change par rapport à la
programmation "classique" séquentielle
Exceptions définir la réaction aux conditions exceptionnelles
rencontrées pendant l’exécution du programme
Événements définir la réaction différents événements (un clic
de souris)
Fils d’exécutions (threads) permettre l’exécution de plusieurs
routines au même temps (ex. plusieurs clients)
22/48
2 Le Flux du Programme : Exceptions, Événements, et Fils
d’Exécution (Threads)
Exceptions et événements
Fils d’exécution (threads) et programmation concurrente
23/48
Une exception simple en Ruby
Le programme ci-dessous peut se planter et indiquer une
erreur (exception) codifiée Errno::ERANGE ou Errno::EDOM
1 a= g e t s ( ) . t o _ f ( )
2 b=Math . l o g ( a∗a−a )
3 puts ( b )
Errno::ERANGE est une classe dérivée d’Exception
24/48
Une exception simple en Ruby
Le programme ci-dessous peut se planter et indiquer une
erreur (exception) codifiée Errno::ERANGE ou Errno::EDOM
1 a= g e t s ( ) . t o _ f ( )
2 b=Math . l o g ( a∗a−a )
3 puts ( b )
Errno::ERANGE est une classe dérivée d’Exception
⇒ La solution : utiliser des exceptions
1 begin
2 a= g e t s ( ) . t o _ f ( )
3 b=Math . l o g ( a∗a−a )
4 puts ( b )
5 rescue Errno : : ERANGE
6 p u t s ( " La f o n c t i o n l o g a r i t h m e ne s ’
a p p l i q u e pas " )
7 end
24/48
Utilisation des exceptions en Ruby
25/48
Utilisation des exceptions en Ruby
25/48
Exemple de programmation dangereuse
Code souvent fonctionnel mais dangereux
1 c l i e n t = TCPSocket . open ( " 1 2 7 . 0 . 0 . 1 " , 1234)
2 c l i e n t . puts ( " s a l u t " )
26/48
Exemple de programmation dangereuse
Code souvent fonctionnel mais dangereux
1 c l i e n t = TCPSocket . open ( " 1 2 7 . 0 . 0 . 1 " , 1234)
2 c l i e n t . puts ( " s a l u t " )
Programmation plus correcte : Prendre en compte des ex-
ceptions possibles – voir une liste dans la documentation de
la classe socket
Errno::ECONNREFUSED connexion refusée par le serveur
Errno::EPIPE connexion fermée avant l’opération put
SocketError impossible de trouver l’IP destination
30/48
Evénements
30/48
Exemple d’événement
1 c l a s s MonListener
2 include ActionListener
3 def actionPerformed ( e )
4 p u t s ’ j e capte un c l i c ’
5 end
6 end
7
8 b t n = J B u t t o n . new ( ’ C l i c k Me ’ )
9 b t n . a d d A c t i o n L i s t e n e r ( MonListener . new )
On observe la classe MonListener qui implémente la mé-
thode actionPerformed
Ligne 9 : l’objet btn indique MonListener comme écou-
teur
31/48
2 Le Flux du Programme : Exceptions, Événements, et Fils
d’Exécution (Threads)
Exceptions et événements
Fils d’exécution (threads) et programmation concurrente
32/48
Fils d’exécution–blocs exécutées en parallèle
33/48
Fils d’exécution–blocs exécutées en parallèle
33/48
Exécution en parallèle
Scénario d’exécution :
Temps Fil principal : Fil secondaire :
0s Sleep(1) puts("Salut")
1s puts("Tout va bien?") Sleep(2)
;
2s Sleep(2) puts("Oui")
3s Puts("Super")) Sleep(1)
34/48
Un exemple plus compliqué
1 x=0
2 f i l _ e x e c = Thread . new do
3 x=7
4 end
5 p u t s ( " x= " +x . t o _ s ( ) )
La valeur affichée est :
35/48
Un exemple plus compliqué
1 x=0
2 f i l _ e x e c = Thread . new do
3 x=7
4 end
5 p u t s ( " x= " +x . t o _ s ( ) )
La valeur affichée est : inconnue
thread plus rapide ⇒ x = 7 ; thread moins rapide ⇒ x = 0
Solution : ajouter fil_exec.join() pour faire le programme
principal attendre le fil d’exécution
1 x=0
2 f i l _ e x e c = Thread . new do
3 x=7
4 end
5 fil_exec . join ()
6 p u t s ( " x= " +x . t o _ s ( ) )
35/48
Mutex : exclusion mutuelle
Étudions le code suivant
1 x=0
2 Thread . new do
3 for i in (1..10000)
4 x=x+1
5 end
6 end
7 for i in (1..10000)
8 y=x
9 x=y+1
10 end
11 p u t s ( x )
La valeur affichée est
36/48
Mutex : exclusion mutuelle
Étudions le code suivant
1 x=0
2 Thread . new do
3 for i in (1..10000)
4 x=x+1
5 end
6 end
7 for i in (1..10000)
8 y=x
9 x=y+1
10 end
11 p u t s ( x )
La valeur affichée est entre 14.000 et 20.000 et très rare-
ment 20000
Solution : une exclusion mutuelle en utilisant un mutex
36/48
Une solution Mutex pratique
37/48
Programme complet Mutex
1 require " thread "
2 mutex = Mutex . new
3 x=0
4 a = Thread . new do
5 for i in (0..10000)
6 mutex . s y n c h r o n i z e do
7 x=x+1
8 end
9 end end
10 f o r i i n ( 0 . . 1 0 0 0 0 )
11 mutex . s y n c h r o n i z e do
12 y=x
13 x=y+1
14 end
15 end
16 a . j o i n ( )
17 p u t s ( x ) 38/48
Messagerie instantanée
Messagerie instantanée : flux entrant + flux sortant
flux entrant : fil principal
flux sortant : fil secondaire
1 r e q u i r e ’ socket ’
2 s e r v e r = TCPServer . open ( 1 2 3 4 )
3 s e s s i o n = s e r v e r . accept ( )
4 Thread . new do
5 w h i l e ( t r u e ) do
6 puts ( session . gets ( ) )
7 end
8 end
9 w h i l e ( t r u e ) do
10 session . puts ( gets ( ) )
11 end
Le client doit se connecter avec TCPSocket.open(...)
39/48
Un serveur Web à base de threads
Point de départ : serveur web sans fils d’exécution :
1
r e q u i r e ’ socket ’
2
s e r v e r = TCPServer . open ( 8 0 8 0 )
3
s e s s i o n = s e r v e r . accept ( )
4
addrtype , p o r t , nom , i p = s e s s i o n . peeraddr
5
s e s s i o n . p u t s ( "HTTP / 1 . 1 200 OK" )
6
session . puts ( " " )
7
s e s s i o n . p u t s ( " <html ><body> " )
8
s e s s i o n . p u t s ( " S a l u t machine " +nom+ " d ’ IP " +
i p . to_s+" et p o r t "+ p o r t . to_s )
9 s e s s i o n . p u t s ( " </ body > </ html > " )
10 s e s s i o n . c l o s e ( )
Rappel : l’inconvénient est le fait que
40/48
Un serveur Web à base de threads
Point de départ : serveur web sans fils d’exécution :
1
r e q u i r e ’ socket ’
2
s e r v e r = TCPServer . open ( 8 0 8 0 )
3
s e s s i o n = s e r v e r . accept ( )
4
addrtype , p o r t , nom , i p = s e s s i o n . peeraddr
5
s e s s i o n . p u t s ( "HTTP / 1 . 1 200 OK" )
6
session . puts ( " " )
7
s e s s i o n . p u t s ( " <html ><body> " )
8
s e s s i o n . p u t s ( " S a l u t machine " +nom+ " d ’ IP " +
i p . to_s+" et p o r t "+ p o r t . to_s )
9 s e s s i o n . p u t s ( " </ body > </ html > " )
10 s e s s i o n . c l o s e ( )
Rappel : l’inconvénient est le fait que ce serveur accepte un
seul client à se connecter
Objectif : un fil d’exécution séparé dédié à chaque client
40/48
L’ajout des fils d’exécution
Après avoir initialisé un objet session, la manipulation de
cet objet doit se faire dans un nouveau fil d’exécution
1 r e q u i r e ’ socket ’
2 s e r v e r = TCPServer . open ( 8 0 8 0 )
3 f o r i i n ( 1 . . 1 0 ) do
4 $session = s e r v e r . accept ( )
5 Thread . new do
6 s e s s i o n = $session
7 adrtype , p o r t , nom , i p = s e s s i o n . peeraddr ( )
8 s e s s i o n . p u t s ( "HTTP / 1 . 1 200 OK" )
9 session . puts ( " " )
10 s e s s i o n . p u t s ( " <html ><body> " )
11 s e s s i o n . p u t s ( " S a l u t machine " +nom+ " d ’ IP
"+ i p . to_s ( ) +" et p o r t "+ p o r t . to_s ( ) )
12 s e s s i o n . p u t s ( " </ body > </ html > " )
13 session . close ( )
14 end end 41/48
1 Sockets : Communication entre machines
42/48
Rappel Swing Jruby et Java
Jruby
1 require " java "
2 i m p o r t j a v a x . swing . JFrame
3 i m p o r t j a v a x . swing . JLabel
4 f e n e t r e = JFrame . new ( " Bonjour " ) ;
5 f e n e t r e . getContentPane ( ) . add ( ( JLabel . new ( " Bonjour " ) ) ) ;
6 f e n e t r e . s e t L o c a t i o n R e l a t i v e T o ( NIL )
7 f e n e t r e . setSize (100 ,500) ;
8 fenetre . setVisible ( true ) ;
9 f e n e t r e . s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame : : DISPOSE_ON_CLOSE) ;
Java
1 i m p o r t j a v a x . swing . JFrame ;
2 i m p o r t j a v a x . swing . JLabel ;
3 p u b l i c c l a s s Bonjour {
4 p u b l i c s t a t i c v o i d main ( S t r i n g [ ] args ) {
5 JFrame f e n e t r e = new JFrame ( " Bonjour " ) ;
6 f e n e t r e . getContentPane ( ) . add ( ( new JLabel ( " Bonjour " ) ) ) ;
7 f e n e t r e . setSize (500 ,500) ;
8 fenetre . setVisible ( true ) ;
9 f e n e t r e . s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . DISPOSE_ON_CLOSE) ;
10 }
11 }
43/48
Un bouton dans un panel dans une fenêtre
45/48
Plusieurs boutons : les layout
On ajoute 20 boutons :
1 f o r i i n 1 . . 2 0 do
2 monPanel . add ( J B u t t o n . new ( "ABCD" ) )
3 end
45/48
Un label contrôlé par 2 boutons
46/48
Un label contrôlé par 2 boutons
46/48
Les événements en Ruby
47/48
Les deux étapes en pratique
1 Définir la classe utilisée pour capter les événements
1 c l a s s MonAction
2 i n c l u d e j a v a . awt . event . A c t i o n L i s t e n e r
3 d e f a c t i o n P e r f o r m e d ( evenement )
4 source=evenement . getSource ( ) . g e t T e x t ( )
5 ...
6 end
7 end
51/48
Swing et Awt
52/48