Table des matières

Voici les données initiales pour réaliser les TP M3101.

TP1

Voici les codes fourni en TD1 :

Pour la question “Mise en place des sémaphores”, utilisez les codes fournis dans le cours pour les programmes : mknamedsem.c, namedsemp.c, namedsemv.c et rmnamedsem.c.

Les question “Application au carrousel” et “Application lecteur/écrivains” ne seront pas notés.

Pour visualiser une trotteuse, utilisez l'option “-update 1” de xclock.

TP2

Utilisez les entêtes :

#!/usr/bin/python
# -*- coding: utf-8 -*-
 
import sys
import struct
import time
import datetime
import locale

Exemple de switch. La commande switch n'existe pas, mais on peut utiliser un tableau qui associe un mot à un identifiant de fonction.

def f1 ():
  print "appel de f1"
 
def f2 ():
  print "appel de f2"
 
var="f1"
 
monSwitch = {
    'f1': f1,
    'f2': f2
}
 
monSwitch [var] ()

On peut passer des arguments à un programme python.

#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
 
def f1 ():
  print "appel de f1"
 
def f2 ():
  print "appel de f2"
 
monSwitch = {
    'f1': f1,
    'f2': f2
}
 
monSwitch [sys.argv[1]] ()

L'appel en bash se fait de la façon suivante

$ chmod a+x monProgrammePython.py
$ ./monProgrammePython.py f1

Pour l'affichage du mode nous devons découper l'entier et isoler des sous-ensembles de bits. Par exemple on peut vouloir découper 0x41ED en 0X4 d'un côté et 0x1ED de l'autre.

fMode = 0x41ED // <=> mode = 040755 <=> mode = 16877
fType = mode >> 12 // => 4
ugo = fMode & 0xFFF // => 0x1ED (héxa) = 0755 (octal) = 493 (décimal)

Les droits “ugo” devraient être découpé en “u” (utilisateur) “g” (groupe) et “o” (autres). De façon optionnel nous pouvons traiter les bits “sst”. Il n'y aura pas de tels fichiers dans le système fournit en exemple.

ugo = 00755
sst = ugo >> 9 & 7 // => 0
u = ugo >> 6 & 7 // => 7
g = ugo >> 3 & 7 // => 5
o = ugo >> 0 & 7 // <=> o = ugo & 7 => 5

Voici quelques fonctions utiles

i = 0x41ED
s = "hex: "+hex (i)+" oct: "+oct (i)+" dec: "+str (i)
// => hex: 0x41ed oct: 040755 dec: 16877

Il y a une erreur dans le support de cours page 49 (listing 35).

$ ./testInode.py  propMode
	00775  =>  prwxrwxr-x
	07775  =>  prwsrwsr-t
	00664  =>  prw-rw-r--
	07664  =>  prwSrwSr-T
	0x41ed =>  drwxr-xr-x
	0x81b4 =>  -rw-rw-r--

Nous utiliserons les fonctions de lecture de fichiers

 fs = open ("td2.MinixFS", "rb")
 fs.seek (addr, 0)
 bytes = fs.read (len)

td2.minixfs.zip

Pour voir le fichier en hexadécimal utilisez emacs et la commande : M-x hexl-mode (Esc-x suivi de hexl-mode) ou “od -x td2.MinixFS” ou “xxd td2.MinixFS”

Voici la structure inode en C

 struct minix_inode {
   __u16 i_mode;
   __u16 i_uid;
   __u32 i_size;
   __u32 i_time;
   __u8 i_gid;
   __u8 i_nlinks;
   __u16 i_zone [9];
 };

Voici comment on peut la lire en python

import struct
inode_fmt = '<HHIIbb9H'
inode_len = struct.calcsize (inode_fmt)
inode_unpack = struct.Struct (inode_fmt).unpack_from

Voici un exemple d'utilisation

fs = open ("td2.MinixFS", "rb") 
fs.seek (i2addr (2), 0)
data = fs.read (inode_len)
inode = inode_unpack (data)
 
print inodeEntry
  => (16893, 66, 160, 1407002500, 67, 3, 6, 0, 0, 0, 0, 0, 0, 0, 0)
 
print hex (inodeEntry[0])
  => 0x41fd
 
iMode = inodeEntry [0]
iUser = inodeEntry [1]
iSize = inodeEntry [2]
iTime = inodeEntry [3]
iGroup = inodeEntry [4]
iLinks = inodeEntry [5]
iZone = inodeEntry[6:]
 
print "%s %d u:%d g:%d %5d %s" % \
      (propMode2str (iMode), iLink, iUser, iGroup, iSize, date2str (iDate))

Voici la structure des entrée de répertoire C

 struct minix_dir_entry {
   __u16 inode ;
   char name [30];
 };

Voici comment on peut la lire en python

import struct
dirEntry_fmt = '<H30s'
dirEntry_len = struct.calcsize (dirEntry_fmt)
dirEntry_unpack = struct.Struct (dirEntry_fmt).unpack_from

Voici un exemple d'utilisation

fs = open ("td2.MinixFS", "rb") 
fs.seek (ua2addr (5), 0)
data = fs.read (dir_len)
dirEntry = dir_unpack (data)
 
print dirEntry [0], dirEntry[1].rstrip ('\x00')

Mise au point de code C

Il existe un outil de mise au point des programmes écrits en C ou C++ : gdb.

Il faut au préalable avoir compilé le vôtre avec l’option “-g”. Au moment de l’exécution, faîtes précéder la commande shell de “gdb - -args”.

gdb --args ./a.out A B C D

Voici quelques commandes :

Toutes ces actions peuvent être réalisées sous emacs:

  • M-x shell : ouvre un terminal
  • M-x compile : lance une compilation avec un lien direct avec les erreurs
  • M-x gdb : lance la mise au point et l'observation d'un programme

TP4

Exemple de code pour dessiner dans un JPanel.

public class Panneau extends JPanel {
  public Panneau (int width, int height) {
    this.width = width;
    this.height = height;
    Dimension size = new Dimension (width, height);
    setMinimumSize (size);
    setPreferredSize (size);
    setDoubleBuffered (true);
  }
 
  public synchronized void update () {
    repaint ();
  }
 
  public void paint (Graphics g) {
    Toolkit.getDefaultToolkit ().sync ();
    Graphics2D g2 = (Graphics2D) g;
    g2.setBackground (Color.WHITE);
    g2.clearRect (0, 0, width, height);
 
    g2.setColor (Color.GREEN);
    g2.fillRect (10, 10, 100, 100);
 
    // ...
    //g2.setColor (rectangle.color);
    //g2.fillRect (rectangle.x, rectangle.y, rectangle.width, rectangle.height);
  }
}

Exemple de code pour tester un objet graphique.

public static final void testComponent (final String title, final Component component) {
  SwingUtilities.invokeLater (new Runnable () {
    public void run () {
      JFrame jFrame = new JFrame (title);
      jFrame.addWindowListener (new WindowAdapter () {
        public void windowClosing (WindowEvent e) {
          System.exit (0);
        }
      });
      jFrame.getContentPane ().add (component, BorderLayout.CENTER);
      jFrame.pack ();
      Dimension screenSize = Toolkit.getDefaultToolkit ().getScreenSize ();
      Dimension size = jFrame.getSize ();
      jFrame.setLocation ((screenSize.width - size.width)/4, (screenSize.height - size.height)/4);
      jFrame.setVisible (true);
    }
  });
}

Il y a 2 possibilités

Pour la solution objets graphique on pourra utiliser le code suivant :

  invalidate ();
  objetGraphiqueADeplacer.setLocation (x, y);
  validate ();

TP5

Pour le TP, vous devez télécharger tp5.zip

Après décompression de l'archive vous obtenez :

Classes utiles pour le TP5 :

tp5/
├── jar
│   └── tp5.jar (Game.class Letter.class Player.class TestParse.class)
├── src
│   └── tp5
│       └── GameNetParse.java
└── ws
    ├── compile.sh
    └── launch.sh

Vous devez modifier la classe GameNetParse.java. Pour compiler et tester, placez vous dans ws.

Le lancement du programme consiste dans le test suivant (inclue dans le jar) :

public class TestParse {
 
    static String[] msgs = {
	"140824 07:09:30 alice: guest bob", // execGuestArg
	"140824 07:09:31 alice: guest grpA:bob", // execGuestArg
	"140824 07:09:32 alice: guest grpA:", // execGuestArg
	"140824 07:09:33 bob: welcome alice@10.0.0.1:8080", // execWelcomeArg
	"140824 07:09:34 alice: welcome bob@10.0.0.2:8081 chalie@10.0.0.1:8082", // execWelcomeArg
	"140824 07:09:35 alice: send 10.0.0.1:8080-A", // execLetterArg
	"140824 07:09:36 alice: answer 10.0.0.1:8082-C", // execLetterArg
	"140824 07:09:37 alice: reject 10.0.0.1:8080-A", // execLetterArg
	"140824 07:09:38 alice: close", // execNoArg
	"140824 07:09:39 bob: full", // execNoArg
	"140824 07:09:40 bob: done 10.0.0.2:8081-[ACD] 10.0.0.2:8082-[BD] 10.0.0.2:8083-F" // execLettersArg
    };
 
    static public void main (String[] arg) {
	Game game = new Game ();
	GameNetParse gnp = new GameNetParse (game);
	for (String msg : msgs) {
	    gnp.parse (msg);
	    System.err.println ();
	}
    }
}

L'objectif du TP est de réaliser l'analyse des lignes précédentes et d'appeler la classe Game (inclue dans le jar) :

public class Game {
    public void netClose (String sender) {
	System.err.println (">close from "+sender);
    }
    public void netFull (String sender) {
	System.err.println (">full from "+sender);
    }
    public void netGuest (String sender, String guest) {
	System.err.println (">guest from "+sender+" to "+guest);
    }
    public void netWelcome (String sender, List<Player> players) {
	System.err.print (">welcome from "+sender);
	for (Player player : players)
	    System.err.print (" "+player);
	System.err.println ();
    }
    public void netSend (String sender, Letter letter) {
	System.err.println (">send from "+sender+" with "+letter);
    }
    public void netAnswer (String sender, Letter letter) {
	System.err.println (">answer from "+sender+" with "+letter);
    }
    public void netReject (String sender, Letter letter) {
	System.err.println (">reject from "+sender+" with "+letter);
    }
    public void netDone (String sender, List<Letter> letters) {
	System.err.println (">done from "+sender+" with "+Letter.toString (letters));
    }
}

Vous disposez des autres classes dans le jar.

package tp5;
public class Player {
    public String name;
    public String ip;
    public int port;
 
    public Player (String name, String ip, String port) {
	this.name = name;
	this.ip = ip;
	this.port = Integer.parseInt (port);
    }
 
    public String toString () { return name+"@"+ip+":"+port; }
}
 
public class Letter {
    public String alpha;
    public String ip;
    public int port;
 
    public Letter (String alpha, String ip, String port) {
	this.alpha = alpha;
	this.ip = ip;
	this.port = Integer.parseInt (port);
    }
}

TP6

Pour le TP, vous devez télécharger tp6.zip

Après décompression de l'archive vous obtenez :

tp6/
├── jar
│   └── tp6.jar
├── src
│   └── tp6
│       └── model
│           └── NetCom.java
└── ws
    ├── compile.sh
    ├── playNet2.sh
    ├── playNet.sh
    ├── playTxt2.sh
    └── playTxt.sh

La commande playTxt.sh vous permet de tester en mode texte.

Vous devez écrire la classe Java NetCom.java pour pouvoir lancer la commande playNet.sh.

Pour cela vous pouvez reprendre la classe recvdata.java (voir le bas de la rubrique Ressources).

Pour retrouver es information IP et port des joueurs, il existe des accesseurs dans deux classes suivantes :

public class Player implements Comparable<Player> {
 
    public String	getName ()	{ return name; }
    public String	getIp ()	{ return ip; }
    public int		getPort ()	{ return port; }
}
public class Game extends StateNotifier implements IGame {
    public Player		getOwner ()		{ return owner;}
}

La classe Packet quand à elle est définie dans l'interface ICom comme suit :

    public class Packet {
	String ip;
	int port;
	String msg;
	public Packet (String ip, int port, String msg) {
	    this.ip = ip;
	    this.port = port;
	    this.msg = msg;
	}
    }

Si vous votre adresse est un IPV6 par défaut ajoutez “-Djava.net.preferIPv4Stack=true”