Interconnexion_avec_les_SGBDs

Transcription

Interconnexion_avec_les_SGBDs
Par$e 4 : Interconnexion entre C# 2.0 et les SGDBs ADO (Ac$veX Data Object) .NET L’interface entre les programmes .NET et les SGBDs se fait grâce à ADO.NET Programme ADO.NET SGBD (en C
#) Il faut juste avoir les bonnes références pour pouvoir u$liser ADO & les objets liés au SGBD. Espaces de nom : ADO : System.Data Oracle : System.Data.OracleClient MySql : MySql.Data.MySqlClient 2 modes d’accès aux BDs 1.  Mode connecté a.  Ouvre une connexion avec la BD b.  Travail avec la BD en lecture écriture c.  Ferme la connexion 2.  Mode déconnecté a. 
b. 
c. 
d. 
e. 
Ouvre une connexion avec la BD Récupère une copie mémoire (par$elle) de la BD Travail avec la copie mémoire Envoie les données modifiées à la BD Ferme la connexion Avantages / Inconvénients des modes d’accès aux BDs •  Mise à jour : une connexion vs plusieurs ⇒ moins de ressources utilisées pour le mode
déconnecté
•  Mise à jour : possibilité de conflits dans le cadre du mode déconnecté (plusieurs u$lisateurs me\ent à jour les mêmes tuples à des temps proches). Pas de conflits avec le mode connecté : la BD est « verrouillée » grâce aux instruc$ons SQL COMMIT / ROLLBACK. •  Mode déconnecté : les données ne sont pas toujours à jour. •  Mode déconnecté : on peut manipuler une rela$on et la faire transiter sur le réseau grâce à un objet (dataset), ce qui n’est pas possible en mode connecté. Créa$on d’une connexion avec une BD Avant de se connecter à un SGBD, il faut construire une chaine de connexion qui comprend différents champs selon le SGBD à a\eindre. Tous ces champs sont séparés par le caractère ‘;’. Champs Significa3on Oracle MySql Database= Nom de la BD X Data Source= Nom Dns de l’hôte sur X X lequel se trouve la BD User Id= Nom X X Password= Mot de passe en clair X X Exemple : string ConnnectionStr = "Database=MaBD;Data
Source=localhost;User Id=alain;Password=xxx";
Créa$on d’une connexion avec une BD •  On précise qu’on veut se connecter à un SGBD en u$lisant la fonc$on : public DBConnection ( string connectionString )
où DB = Oracle|MySql
Ex : MySqlConnection ConnectionBD = new
MySqlConnection(ConnnectionStr);
•  Ensuite on se connecte au SGBD grâce à la fonc$on : public override void Open ()
Ex : ConnectionBD.Open();
•  Puis on exécute des requêtes (voir plus loin) •  Enfin on ferme la connexion avec le SGBD grâce à la fonc$on :
public override void Close ()
Ex : ConnectionBD.Close();
Créa$on d’une requête •  Pour créer une requête, on fait appel à la fonc$on suivante : public DBCommand CreateCommand ()
La créa$on d’une variable DBCommand, se fait grâce à l’objet DBConnection précédemment crée. Ex : MySqlCommand UpdateCmd =
ConnectionBD.CreateCommand();
•  Propriétés de la classe DBCommand :
1.  public abstract string CommandText { get;
set; } Texte associé à la commande SQL à exécuter. A\en$on aux caractères protégés !! 2.  public abstract int CommandTimeout { get;
set; }
Durée pendant laquelle on a\end la réponse. Exécu$on d’un requête L’exécu$on d’une requête SQL se fait grâce à des méthodes de la classes DBCommand. Cependant, il faut dis$nguer 3 cas : 1.  La requête ne retourne aucun résultat (Insert, Update, Create, Commit, …), 2.  La requête rend un unique résultat, 3.  La requête rend un ensemble de tuples. Exécu$on d’une requête (cas 1) Il faut faire appel à la fonc$on membre public abstract int ExecuteNonQuery ()
Elle retourne le nombre de ligne qui ont été modifiées par la requête. Ex : On veut remplacer le prénom Alain par Bob sur toute la base et connaître le nombre de lignes modifiées. string UpdateStr = "Update MaRel
SET Prenom = \"bob\"
WHERE Prenom = \"Alain\"";
MySqlCommand UpdateCmd =
ConnectionBD.CreateCommand();
UpdateCmd.CommandText = UpdateStr;
int i = UpdateCmd.ExecuteNonQuery();
Console.WriteLine(i);
Exécu$on d’un requête (cas 2) Il faut faire appel à la fonc$on membre public abstract Object ExecuteScalar ()
Elle retourne la première colonne du premier tuple lié au résultat. Tous les autres données sont ignorées. A\en$on au transtypage!! Ex : On veut connaître le nombre de tuples dans la rela$on. string CountStr = "select count(*) from MaRel";
MySqlCommand CountCommand =
ConnectionBD.CreateCommand();
CountCommand.CommandText = CountStr;
Int64 Combien = (Int64)
CountCommand.ExecuteScalar();
Console.WriteLine(Combien);
Exécu$on d’un requête (cas 3) Il faut faire appel à la fonc$on membre public DBDataReader ExecuteReader ()
Elle ini$alise un objet de la classe DBDataReader qui va nous perme\re de manipuler le résultat de la requête. Cet objet est similaire à un curseur SQL. Ex : On veut connaître le nom, le prénom et l’âge des personnes recensées dans la rela$on. string SelectStr = "SELECT Nom, Prenom,
Age FROM MaRel ";
MySqlDataReader MonReader =
SelectCommand.ExecuteReader();
Exécu$on d’un requête (cas 3) Il faut ensuite manipuler l’objet DBDataReader pour pouvoir lire dans le flux résultat. •  La lecture se fait grâce à la fonc$on : public abstract bool Read ()
Ce\e fonc$on renvoie vrai si un nouveau tuple existe dans le flux, faux sinon. Ex : while (MonReader.Read())
{
… // traitement du tuple
}
Exécu$on d’un requête (cas 3) Pour accéder aux divers champs du tuple, nous avons plusieurs possibilités. L’objet DBDataReader créé précédemment peut être vu comme un tableau d’objet contentant exactement le nombre de champs résultats. Pour accéder au i° champs, on peut y accéder : 1.  Grace à la nota$on [i-­‐1] 2.  Soit en nommant explicitement le champs Dans les 2 cas, il faut u$liser un transtypage ! Ex :
string Nom = (string) MonReader[0];
string Prenom = (string)MonReader
["Prenom"]; Exécu$on d’un requête (cas 3) •  Si on ne souhaite pas u$liser de transtypage, on peut u$liser une des fonc$ons : public abstract TypePrimitif
GetTypePrimitf (int Pos)
Où Pos désigne le i° champs résultat. Il existe autant de fonc$ons que de type primi$f Ex : int age = MonReader.GetInt32(2);
string Nom = MonReader.GetString
(0);
Exécu$on d’un requête (cas 3) •  Dans tous les cas, il faut faire a\en$on si la valeur vaut
null. Dans ce cas, le transtypage (la conversion) est impossible – mais il n’y a pas de propaga$on d’erreur! •  On u$lise la fonc$on public abstract bool IsDBNull ( int
ordinal) avant de faire un transtypage. Ex : int age;
if (!MonReader.IsDBNull(2))
age = MonReader.GetInt32(2);
Requête paramétrée Il arrive souvent qu’on ne connaisse pas toutes les valeurs d’une requête à l’avance (inser$on d’un nouveau tuple, requête nécessitant une saisie u$lisateur, …). Pour construire de telles requêtes et les faire exécuter par le SGDB, il suffit de retarder au maximum la créa$on de la requête jusqu’à avoir connaissance de chacun des paramètre et enfin de construire la chaine représentant la requête SQL. Ex : on veut connaitre le nom et le prénom de toutes les personnes dont l’âge est supérieur à une valeur saisie au clavier. int age;
string Chaine = Console.ReadLine();
if (Int32.TryParse(Chaine, out age))
{
string SelectStr = "Select Nom, Prenom
FROM MaRel
Where Age > " + age;
…
}
Mode déconnecté •  On u$lise les objets de classe DbDataAdapter pour servir d’interface entre la BD présente sur le serveur et sa « version » locale. •  Les objets de types DataSet qui représentent la « version » locale de la BD (souvent une por$on d’une table – une vue). Classe DbDataAdapter •  Constructeur : protected DbDataAdapter ()
•  Propriétés (lecture / écriture): – 
– 
– 
– 
SelectCommand
InsertCommand
DeleteCommand
UpdateCommand
Elles a\endent (retournent) un objet de type DbCommand.
•  Il faut préciser la chaine de connexion dans la propriété Ex : DbDataAdapter DA = new DbDataAdapter();
DA. SelectCommand = new DbCommand(SelectStr,
connectionString);
Classe DbDataAdapter •  Il faut remplir l’objet de type DataSet en u$lisant une des méthodes Fill : public override int Fill (DataSet dataSet) Ajoute ou actualise les lignes de DataSet pour qu'elles correspondent à celles de la source de données en u$lisant le nom de DataSet, et crée un DataTable appelé "Table". public int Fill (DataSet dataSet, string srcTable) srcTable :Nom de la table source à u$liser pour le mappage de tables. public int Fill ( DataSet dataSet, int startRecord,
int maxRecords, string srcTable)
startRecord : Numéro de l'enregistrement de base zéro par lequel commencer. maxRecords : Nombre maximal d'enregistrements à récupérer. Valeur de retour : Nombre de lignes correctement ajoutées ou actualisées dans DataSet
Ex : DataSet DS = new DataSet();
DA.Fill(DS);
Classe DbDataAdapter •  Si on a modifié l’objet de type DataSet dans le cours du programme, on met à jour sa version sur le SGBD en u$lisant la méthode Update : public override int Update (DataSet
dataSet)
Classe DataSet
•  Peut être vu comme une BD avec plusieurs tables (nommées ou non). On accède à une rela$on soit : –  En indiçant l’objet DataSet –  En nommant explicitement la rela$on souhaitée Ex : DS[0] représente le résultat de la requête Select. Une table est de type DataTable. Classe DataTable
•  Représenta$on d’une table en mémoire. On accède aux colonnes via la propriété Columns et aux lignes via la propriété Rows. •  On accède à une colonne soit : –  En indiçant l’objet DataTable.Columns
–  En nommant explicitement la colonne souhaitée •  On accède à une ligne en indiçant l’objet DataSet.Rows. Ex :
foreach(DataRaws ligne in DataSet.Rows)
Console.WriteLine (‘’Nom ‘’ + ligne[0]);
Par$e 5 : Classes facilitant la programma$on Envoi d’email •  But : rendre transparent le protocole SMTP •  On u$lise les classes MailAddress ,
MailMessage et SmtpClient
•  Constructeurs public MailAddress (string email) public MailMessage (
MailAddress From, MailAddress To)
Propriétés de la classe MailMessage •  Corps du message : public string Body { get; set; }
•  Sujet : public string Subject { get; set; } •  Champs CC ou CCI public MailAddressCollection CC { get; }
public MailAddressCollection Bcc { get; }
•  Pour ajouter des personnes (en copie), on u$lise la méthode .Add() sur les champs CC (ou Bcc) •  Possibilité de définir des fichiers a\achés avec la propriété Attachments
La classe SmtpClient
•  Constructeurs : public SmtpClient ( string host )
public SmtpClient ( string host, int
port )
•  Envoi de messages : public void Send ( MailMessage message)
•  Possibilité d’u$lisé du SSL (Secure Sockets Layer) pour chiffrer la connexion via la propriété EnableSsl. Interroga$on de site web •  But : faciliter la manipula$on du protocole HTTP. •  U$lisa$on de la classe HttpWebRequest. Ce\e classe dérive de la classe WebRequest. •  On crée une requête Web avec la méthode Create
() public static WebRequest Create
( string requestUriString )
•  On transtype le résultat dans un objet de type HttpWebRequest
HttpWebRequest MaReq =
(HttpWebRequest) WebRequest.Create
(Url); Propriétés sur les HttpWebRequest •  Propriété Method : permet de spécifier le type de requête (GET ou POST). public override string Method { get; set; }
MaReq.Method = "GET";
•  Propriété ContentType : permet de spécifier l’entête HTTP (U$le quand on fait des requêtes de type POST). public override string ContentType { get;
set; }
MaReq.ContentType="application/x-www-formurlencoded";
Propriétés sur les HttpWebRequest •  Propriété Credentials : permet de spécifier les informa$ons d’authen$fica$on pour la demande public override ICredentials Credentials { get;
set; }
MaReq.Credentials =
CredentialCache.DefaultCredentials;
•  Méthode GetReponse () : permet d’obtenir la réponse du serveur web. public override WebResponse GetResponse ()
HttpWebResponse response =
(HttpWebResponse) MaReq.GetResponse();
HttpWebRequest et requête POST •  Si on fait une requête POST, on doit envoyer aussi le corps de la requête. •  On ob$ent le flux sous jacent grâce à la méthode GetRequestStream(). Ensuite, on construit le StreamWriter associé. Stream envoi = MaReq.GetRequestStream();
StreamWriter SW = new StreamWriter(envoi);
•  Il faut aussi fixé la taille de la requête envoyée grâce à la propriété ContentLength. MaReq.ContentLength = Req.Length+1;
•  On n’oublie pas d’envoyer la requête HTTP.
SW.WriteLine (Req);
La classe HttpWebResponse
•  Con$ent les informa$ons d’une réponse HTTP. •  Une fois l’objet de type HttpWebResponse obtenu, on fait appel à la méthode GetResponseStream() pour obtenir le flux sous-­‐jacent à la connexion. Stream streamResponse = response.GetResponseStream();
•  On récupère un StreamReader puis on manipule le flux de manière classique StreamReader SR = new StreamReader
(streamResponse);
string RepWeb = SR.ReadToEnd();
Ges$on des cookies •  Après authen$fica$on, on récupère le cookie lié à la session grâce à la propriété Cookies. CookieCollection MonCookie =
response.Cookies;
•  Grâce à la propriété CookieContainer, on crée un vecteur de cookies, auquel on ajoute le cookie de cession récupérer précédemment. MaReq.CookieContainer = new
CookieContainer();
MaReq.CookieContainer.Add(MonCookie);
•  Le reste de la requête ne change pas. Par$e 6 : Programma$on réseau en C Socket -­‐ Unix •  Besoin d’une « ressource » (mémoire partagée) pour faire communiquer 2 processus. •  La façon de nommer ce\e ressources s’appelle le domaine d’adressage : –  Dans le mode Unix (au sein de la même machine), c’est un nom de fichier. •  Les adresses qui appar$ennent à un domaine d'adressage font par$e d'une famille d'adresses (Address Family) •  Sous Unix, les E/S (hors mis les files de messages) se font via la table des descripteurs de fichier •  U$lisa$on de fonc$ons système create(), open(), pipe(), thread(), … Socket -­‐ Unix • 
• 
Chaque socket ac$ve est iden$fiée par un en$er (>0) appelé descripteur de socket (sd) Il est placé dans la même table que les descripteurs de fichier Num du descripteur de fichier ≠ num du descripteur de socket
sd
Table des fds
Utilisateur
Table des
« fichiers » ouverts
(file table)
Table des i-nœud des
« fichiers » ouverts
Système
Possibilité d’utiliser les fonctions systèmes vues sur les fichiers :
read(), write(), close(), …
La fonc$on socket() But : créa$on d’un point de communica$on & obten$on d’un descripteur de socket •  On voudrait u$liser la fonc$on open() Solution impossible car :
•  forte dissymétrie entre le client et le serveur (le processus doit
connaître quel rôle jouer)
•  Problème avec le mode de communication utilisant un réseau
•  On va u$liser la fonc$on socket() #include <sys/socket.h>
int socket (int domain, int type, int protocol);
La fonc$on socket() int socket (int domain, int type, int protocol);
•  domain : famille de protocole (Protocl Familly) de communica$on à u$liser avec la socket (PF_INET, PF_LOCAL) •  type : type de connexion souhaitée –  SOCK_STREAM (mode connecté) –  SOCK_DGRAM (mode non connecté) •  protocol : spécifie le protocole de transport à u$liser. Généralement mis à 0 car l’associa$on entre la famille de protocole et le type de connexion permet sa spécifica$on implicite int
int
sd = socket (PF_INET, SOCK_STREAM, O) // socket mode connecté
sd = socket (PF_INET, SOCK_DGRAM, O) //socket mode non connecté
(adresse,port) en C Représenta$on du couple •  typedef unisgned short int sa_family_t;
struct sockaddr
{
sa_family_t sa_family; // protocole
char sa_data [14]; // adresse
};
•  struct sockaddr_in
{
sa_familty_t sin_family; //AF_INET
uint16_t sin_port; // # Port
struct in_addr sin_addr; //@ ip sur 4 octets
}
struct in_addr
{
in_addr_t s_addr; // adresse IPv4 dans l'ordre réseau
};
Représenta$on des octets sur le réseau (1) 2 représenta$ons possible : 1.  Les octets de poids forts devants Big Endian SUN, HP, Motorola, … 2.  Les octets de poids faible devant Li\le Endian Intel Ø  Les réseaux sont hétérogènes Ø  Les couches réseaux, Internet & transport ne modifient pas l’ordre des octets Ø  Numéro de port inscrit dans l’entête des datagrames • 
C’est la représentation Big Endian qui est utilisée dans les
réseaux. On parle aussi de représentation NBO : Network
Byte Order
Représenta$on des octets sur le réseau (2) 4 le\res pour 4 macro afin de rendre le code « portable » •  s : short (num port par ex) •  l : long (@ ip par ex) •  h : host (machine sur laquelle on exécute le programme) •  n : network (réseaux sur lequel on envoie les données) #include <sys/type.h>
u_long htonl (u_long); // host to network –
u_short htons (u_short); // host to network
u_long ntohl (u_long); // network to host –
u_short ntohs (u_short); // network to host
long
– short
long
– short
Ex : affectation du port 13 (daytime) à une variable Adr de type
sockaddr_in : Adr.sin_port = htons(13);
Conversion d’adresse •  adresse réseau fournie par nota$on pointée (ex : 192.168.1.101) •  La structure sockaddr_in a\end une adresse IPV4 dans l’ordre réseau, mise sous forme d’un en$er. U$lisa$on de 2 fonc$ons : #include <arpa/inet.h>
in_addr_t inet_addr (const char *cp);
// Conver$ une adresse décimale pointée en un en$er qui respecte le NBO char *
inet_ntoa (struct in_addr in);
// Conver$ un en$er qui respecte le NBO en une adresse décimale pointée !! Ces 2 fonc$ons ne sont pas symétriques
Adr.sin_addr.s_addr = inet_addr(“192.168.1.100”);
cout <<
inet_ntoa(Adr.sin_addr);
La fonc$on bind() int bind (int sockfd, struct sockaddr * my_addr,
socklen_t addrlen);
• 
• 
• 
• 
sockfd : descripteur de la socket my_addr : structure spécifiant l’adresse local avec laquelle bind() doit travailler addrlen : en$er donnant la taille de l’adresse Remarques : 1.  my_addr doit marcher pour tout type d’adresse (Unix, réseaux, …) mais on est en C => pas de surcharge, pas de généricité mais possibilité d’u$liser des astuces 2.  passage d'un pointeur * my_addr (taille constante = 4 octets) vers l'adresse (de type struct sockaddr) dont la taille (en octet) dépend du domaine d'adressage La fonc$on bind() (2) •  D’un manière générale, la struct sockaddr est définie comme suit (pseudo généricité oblige) : typedef unisgned short int sa_family_t;
struct sockaddr
{
sa_family_t sa_family; // protocole
char sa_data [14]; // adresse
};
•  Pour les serveur unix : struct sockaddr_un
{
sa_family_t sun_family; // AF_LOCAL
char sun_path [108];
// nom de l'i-node
};
La fonc$on bind() (3) int bind (int sockfd, struct sockaddr * my_addr,
socklen_t addrlen); Préparation de
l’adresse
Int sd = socket (PF_INET, SOCK_DGRAM, 0);
struct sockaddr_in Adr;
memset (& Adr, 0, sizeof (Adr));
Adr.sin_family = AF_INET;
Adr.sin_port = htons(port);
Adr.sin_addr.s_addr = inet_addr(adresse_ip);
bind (sd, & Adr, sizeof(Addr));
(sockaddr * )
Transtypage L
•  A\ente d’un pointeur sur une struct
•  de type sockaddr *
La fonc$on bind() (4) bind (sd, (:: sockaddr *) & Adr, sizeof (Adr));
•  idée : u$liser reinterpret_cast car il ne "réfléchit" pas et conver$t un pointeur dans un autre type de pointeur sans problème. bind (sd,
reinterpret_cast <::sockaddr *> (& Adr),
sizeof (Adr));
Bigraphe => non
utilisable en C
•  U$liser une macro pour préparer l’avenir #define CASTSOCK(x)reinterpret_cast < ::sockaddr *> (x)
bind (sd, CASTSOCK (& Adr), sizeof(Adr));
Problèmes liés à TCP 1. 
2. 
Ges$on de la file d’a\ente int listen (int sockfd, int backlog);
– 
sockfd : descripteur de la socket –  backlog : nombre de connexions maximal. Généralement posi$onné avec SOMAXCONN
Mise en place du circuit virtuel bi-­‐ direc$onnel dédié à chaque client int
accept(int sockfd, … );
retourne une descripteur de socket perme\ant la communica$on client / serveur La fonc$on accept() int accept (int socket,
struct sockaddr * addr,
socklen_t * addrlen);
–  Addr : adresse du client, remplie automa$quement grâce à la couche réseau –  Addrlen : taille de la structure contenant l’adresse du client; c’est donc une donnée résultat ! –  Renvoie le descripteur de socket lié au client C’est une
donnée !!
int bind (int sockfd, struct sockaddr * my_addr,
socklen_t addrlen);
La fonc$on accept() (2) sockaddr_un AdrClient ;
socklen_t LgAdrClient = sizeof (AdrClient);
int sdComm = accept (sdCnx,
CASTSOK (& AdrClient),
& LgAdrClient);
•  U$lisa$on de la macro CASTSOCK
•  Pb : reinterpret_cast ne "réfléchit" pas pour conver$r un pointeur dans un autre type de pointeur. On peut obtenir un segmentation
fault si la longueur de l’adresse client reçue trop longue (> sizeof
(AdrClient)) •  LgAdrClient = paramètre donnée-­‐résultat Serveur Internet
Int ServeurSockInStream(adresse_ip, port)
{
int sd = socket(PF_INET,SOCK_STREAM,0);
struct sockaddr_in Adr;
Init_AddrIn(&Adr, adresse_ip, port);
bind(sd, CASTSOCK (&Adr), sizeof (Adr));
listen (sd, SOMAXCONN);
for( ; ; ) {
sockaddr_in AdrClient ;
socklen_t LgAdrClient = sizeof (AdrClient);
int newsd = accept (sd, CASTSOCK (&AdrClient),
& LgAdrClient);
…
La fonc$on connect()(1) but : établir une connexion entre les processus client et serveur via la socket sd
int connect(int sockfd,
const struct sockaddr * serv_addr,
socklen_t addrlen);
•  sockfd : descripteur de la socket •  serv_addr : structure spécifiant l’adresse locale du serveur avec lequelle connect() doit établir la connexion •  addrlen : en$er donnant la taille de l’adresse Pb : on travaille avec une struct de type sockaddr_in
et non sockaddr
Idée : utiliser le même reinterpret_cast que dans la
fonction bind()
La fonc$on connect()(2) #define CASTSOCK(x)reinterpret_cast < ::sockaddr *> (x)
int sd = socket(...);
sockaddr_in ServAdr;
… //initialisation de l’adresse du serveur
connect(sd,CASTSOCK( & ServAdr ), sizeof(ServAdr));
Pas d’appel à bind() chez le client, la fonction connexion
se charge de renseigner les éléments manquants
Émission de message (TCP) •  On connaît déjà l’interlocuteur (le serveur) •  On a voulu une API proche des E/S sur les fichiers Utilisation de la fonction write()pour écrire sur la socket
ssize_t write(int sockfd,
const void * buffer, size_t length);
Possibilité d’envoyer des messages « spéciaux » avec
send()
ssize_t send(int sockfd,
const void * buffer, size_t length,
int flag);
Valeurs de flag :
•  0 : Non opérant, équivalant à write()
•  MSG_OOB : émission de message urgent (Out Of Band)
Récep$on de message (TCP) •  fonc$ons symétriques aux fonc$ons d’émission de message ssize_t read(int sockfd,
const void * buffer, size_t length);
ssize_t recv(int sockfd,
const void * buffer, size_t length,
int flag);
Valeurs de flag :
•  0 : Non opérant, équivalant à read()
•  MSG_OOB : réception de message urgent (Out Of Band)
•  MSG_PEEK : permet d’aller voir quel message on a reçu sans le
lire, cad sans qu’il soit retiré du buffer
En résumé ! Serveur
Client
sd = socket()
sd = socket()
bind(sd)
connect(sd)
sendto(sd)
recvfrom(sd)
sendto(sd)
close(sd)
Echanges
recvfrom(sd)
close(sd)
Non
nécessaire
Émission de message UDP (1) type
– 
– 
– 
– 
emetre (où, quoi, à qui);
type = ssize_t
emetre ó sendto
Où : Sur la socket sd précédemment définie Quoi : du contenu dont la défini$on ne dépend pas du type const void * buffer
il faut aussi passer la taille de ce contenu (comme dans l’écriture sur des fichiers, pipe, …) size_t length
–  À qui : au serveur (client) qu’on vient de définir dans Init_AddrIn()
const struct sockaddr *to
socklen_t tolen
Émission de message UDP (2) ssize_t sendto (
int socket,
const void * buffer, size_t length,
int flags,
const struct sockaddr *to,
socklen_t tolen); 2 valeurs pour le drapeau :
•  MSG_DONTWAIT : pour envoi de messages urgents
•  0 : pour envoi de messages « classique »
On va avoir les mêmes problème de transtypage qu’avec
la fonction connect()sur l’adresse du destinataire
On réutilise la macro CASTSOCK()
Récep$on de message (UDP) Fonc$on symétrique à la fonc$on sendto(), mais on ne doit plus déterminer à qui envoyer le message, mais de qui il provient : ssize_t recvfrom ( int socket,
const void * buffer, size_t length,
int flags,
Adresse de
l’émetteur
const struct sockaddr *to,
socklen_t * tolen); 1 drapeau en plus : MSG_PEEK (même sémantique que pour recv())
Même problème que dans la fonction sendto()
pour le type de l’adresse de l’émetteur
En résumé ! Serveur
Client
sd = socket()
sd = socket()
bind(sd)
connect(sd)
sendto(sd)
recvfrom(sd)
sendto(sd)
close(sd)
Echanges
recvfrom(sd)
close(sd)
Non
nécessaire
En par$culier, côté serveur sockaddr_in Addr;
…//initialisation de l’adresse
socklen_t LgAddr = sizeof (Addr);
NbLus = Recvfrom (sd, BufferRd, MaxSz, 0,
CASTSOCK (&Addr), & LgAddr);
// Préparer la réponse (dans un BufferWr)
Sendto (sd, BufferWr, NbBytes, 0,
CASTSOCK (&Addr), & LgAddr);
En par$culier, côté client sockaddr_in Addr;
socklen_t LgAddr = sizeof (Addr);
// Préparer le message : BufferWR
// Préparer l'adresse du serveur
Sendto (sd, BufferWR, NbBytes, 0,
CASTSOCK (&Addr), LgAddr);
NbLus = Recvfrom (sd, BufferRd, MaxSz, 0, 0, 0);
Pas terrible !!

Documents pareils