Samote
07/04/2007, 12h18
Réaliser une connection simple entre deux ds par wifi
Intro : Nous réaliserons un programme simple côté serveur puis côté client. Ce programme se chargera d'afficher un texte si l'écran tactile de l'autre ds est touché.
Nous utiliserons PALib pour sa fonction PA_ConnectWifiWFC(). Les autres fonctions utilisées proviendrons de la lib wifi.
Pour communiquer les ds vont utiliser des sockets. Les données seront envoyées et reçues par les fonctions send() et recv().
Avant de commencer nous allons placé ces deux lignes en haut de la fonction main :
PA_InitWifi(); // Pour initialiser le wifi
PA_ConnectWifiWFC(); // Pour se connecter en utilisant les paramètres WFC
1) Côté serveur :
1. La structure sockaddr_in :
struct sockaddr_in {
short int sin_family; // Famille d'adresse
unsigned short int sin_port; // Numéro de Port
struct in_addr sin_addr; // Adresse Internet (ip)
unsigned char sin_zero[8];
};
Cette structure va contenir les adresses et les ports du client et du serveur.
Nous allons donc en déclarer deux :
struct sockaddr_in addresseserveur; // information du serveur
struct sockaddr_in addresseclient; //information du client
Puis "remplir" celle concernant le serveur :
addresseserveur.sin_family = AF_INET;
//pour la famille nous utilisons AF_INET
addresseserveur.sin_port = htons(8888);
//pour le port nous utilisons la fonction htons() avec en paramètre le numéro du port
addresseserveur.sin_addr.s_addr = 0;
//pour l'adresse ip nous mettons 0 car une ip a déjà été attribué a la ds.
Nous récupèrerons les informations concernant le client plus tard.
2. Creation du socket :
Pour créer un socket il faut utiliser la fonction :
int socket(int domain, int type, int protocol);
Elle renvoie un descripteur de socket que nous récupérerons dans une variable de type int.
Nous y ferons appelle ainsi :
int notresocket = 0;
notresocket = socket(AF_INET, SOCK_STREAM, 0);
3. Association a un port :
Une fois le socket créé il faut l'associer avec un port. Pour cela nous utiliseront bind().
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
Nous y ferons appelle ainsi :
bind(notresocket, // le descripteur de socket
(struct sockaddr *)&addresseserveur, // les infos du serveur
sizeof(addresseserveur)); // la taille de la structure des info du serveur
4. Écouter sur le socket :
Nous allons désormais écouter sur le socket a l'aide de listen().
int listen(int sockfd, int backlog);
Nous y ferons appelle ainsi :
listen(notresocket, // le descripteur de socket
1); // le nombre de connection autorisée
5. Accepter les connections :
Pour finir nous allons accepter les connections entrante grace a accept().
int accept(int sockfd, void *addr, int *addrlen);
Cette fonction bloque le programme jusqu'à ce qu'une connections soit accepter.
Elle renvoie une nouveau descripteur de socket que nous allons récupérer dans une nouvelle variable de type int.
Nous y ferons appelle ainsi :
int notresocketfinale = 0;
notresocketfinale = accept(notresocket, //ancien descripteur
(struct sockaddr *)&addresseclient,// recuperation des info client
(int*)sizeof(struct sockaddr_in)); //taille de la structure sockaddr_in
2) Côté client :
1. L'ip du serveur :
Les adresse ip sont contenu dans des variable de type long.
long ipserveur = 0;
Pour transformer une chaîne de caractère en ip nous allons utiliser la fonction inet_addr()
Par exemple :
ipserveur = inet_addr("86.204.83.214");
Si votre ip est sous la forme d'un nom de domaine il faut utiliser la fonction gethostbyname().extern struct hostent * gethostbyname(const char * name);
Elle renvoie une structure de type hostent qui contient diverse information sur le nom de domaine.
struct hostent domaine; // on declare une structure hostend
domaine = *gethostbyname("samote.dyndns.org"); //on récupère les info du dns
L'ip du serveur est contenu dans le membres .h_addr_list
ipserveur = **domaine.h_addr_list;
2. sockaddr_in pour les infos du serveur :
Nous avons recuperé l'ip dans un long maintenant nous allons devoir crée une structure sockaddr_in :
struct sockaddr_in addresseserveur;
addresseserveur.sin_family = AF_INET; // AF_INET pour la famille
addresseserveur.sin_port = htons(8888); // meme port que pour le serveur
addresseserveur.sin_addr.s_addr = ipserveur; // on utilise la variable ip serveur
3. Creation du socket :
Nous allons passer a la création du socket :
int notresocketfinale = 0; // le descripteur de socket
notresocketfinale = socket(AF_INET, SOCK_STREAM, 0); // création du socket
4. La connection au serveur :
La connection au serveur de fait a l'aide de la fonction connect().
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
Elle doit être appelée pendant que le serveur fait appel a accept() :
connect(notresocketfinale, // le descripteur de socket
(struct sockaddr *)&addresseserveur, // les infos du serveur
sizeof(struct sockaddr)); // taille de la structure sockaddr_in
3) send() et recv() :
Nos deux ds sont désormais connectées, nous allons donc pouvoir utiliser send() et recv() pour transférer des données.
Notez que la ds serveur doit être allumer avant la ds client car connect() doit être appelé après accept(). Pour éviter se problème vous pouver faire appel a connect() lors de la pression d'une touche.
1. send() :
Voici le prototype de la fonction send :
int send(int sockfd, // le descripteur de socket
const void *msg, // un pointeur sur les données a envoyer
int len, // taille des données en octet
int flags); // mettre flag a 0
Il n'y a pas de type définie pour les données, on peut envoyer ce que l'on veut : variables de tout type, tableaux , structures...
2. recv() :
Voici le prototype de la fonction recv :
int recv(int sockfd, // le descripteur de socket
void *buf, // un pointeur sur le buffer
int len, // la taille maximal du buffer
unsigned int flags); // mettre flag a 0
Le buffer est la variable qui va recevoir les données.
La fonction recv() et une fonction bloquante, c'est a dire qu'elle bloque l'exécution du programme jusqu'à la réception d'un paquet.
Pour éviter cela on peut rendre le socket non bloquant :
u8 erreur = 1; // variable pour vérifier les erreurs
ioctl(notresocketfinale, // le descripteur de socket
FIONBIO,
&erreur); //la variable d'erreur
En mode non bloquant recv() renvoie -1 si il n'y a pas de paquet reçu.
4) Exemple d'utilisation :
Maintenant que les deux ds peuvent communiquer, nous allons réaliser la partie du programme qui affiche un texte lorsque l'écran de l'autre ds est touché.
Nous allons d'abord déclarer deux booléens :
bool donnesenvoyees = 0; // la variable que nous enverons avec send()
bool buffer = 0; // la variable qui va contenir les données reçues
Maintenant voici le code de la boucle principale :
while (1)
{
// donnesenvoyees vaut 1 si l'écran est touché
donnesenvoyees = Stylus.Held;
// on envoie la variable donnesenvoyees a l'autre ds
send(notresocketfinale, &donnesenvoyees, 1, 0);
// on reçois les données de l'autre ds, le buffer va être modifié
recv(notresocketfinale, &buffer, 1, 0);
//Si buffer vaut 1, l'écran de l'autre ds a été touché
if (buffer == 1)
{
// alors on affiche le texte
PA_OutputSimpleText (1, 16, 12, "Salut");
}
PA_WaitForVBL();
}
C'est la fin de ce tuto, j'espère que sa vous aura été utile.
Intro : Nous réaliserons un programme simple côté serveur puis côté client. Ce programme se chargera d'afficher un texte si l'écran tactile de l'autre ds est touché.
Nous utiliserons PALib pour sa fonction PA_ConnectWifiWFC(). Les autres fonctions utilisées proviendrons de la lib wifi.
Pour communiquer les ds vont utiliser des sockets. Les données seront envoyées et reçues par les fonctions send() et recv().
Avant de commencer nous allons placé ces deux lignes en haut de la fonction main :
PA_InitWifi(); // Pour initialiser le wifi
PA_ConnectWifiWFC(); // Pour se connecter en utilisant les paramètres WFC
1) Côté serveur :
1. La structure sockaddr_in :
struct sockaddr_in {
short int sin_family; // Famille d'adresse
unsigned short int sin_port; // Numéro de Port
struct in_addr sin_addr; // Adresse Internet (ip)
unsigned char sin_zero[8];
};
Cette structure va contenir les adresses et les ports du client et du serveur.
Nous allons donc en déclarer deux :
struct sockaddr_in addresseserveur; // information du serveur
struct sockaddr_in addresseclient; //information du client
Puis "remplir" celle concernant le serveur :
addresseserveur.sin_family = AF_INET;
//pour la famille nous utilisons AF_INET
addresseserveur.sin_port = htons(8888);
//pour le port nous utilisons la fonction htons() avec en paramètre le numéro du port
addresseserveur.sin_addr.s_addr = 0;
//pour l'adresse ip nous mettons 0 car une ip a déjà été attribué a la ds.
Nous récupèrerons les informations concernant le client plus tard.
2. Creation du socket :
Pour créer un socket il faut utiliser la fonction :
int socket(int domain, int type, int protocol);
Elle renvoie un descripteur de socket que nous récupérerons dans une variable de type int.
Nous y ferons appelle ainsi :
int notresocket = 0;
notresocket = socket(AF_INET, SOCK_STREAM, 0);
3. Association a un port :
Une fois le socket créé il faut l'associer avec un port. Pour cela nous utiliseront bind().
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
Nous y ferons appelle ainsi :
bind(notresocket, // le descripteur de socket
(struct sockaddr *)&addresseserveur, // les infos du serveur
sizeof(addresseserveur)); // la taille de la structure des info du serveur
4. Écouter sur le socket :
Nous allons désormais écouter sur le socket a l'aide de listen().
int listen(int sockfd, int backlog);
Nous y ferons appelle ainsi :
listen(notresocket, // le descripteur de socket
1); // le nombre de connection autorisée
5. Accepter les connections :
Pour finir nous allons accepter les connections entrante grace a accept().
int accept(int sockfd, void *addr, int *addrlen);
Cette fonction bloque le programme jusqu'à ce qu'une connections soit accepter.
Elle renvoie une nouveau descripteur de socket que nous allons récupérer dans une nouvelle variable de type int.
Nous y ferons appelle ainsi :
int notresocketfinale = 0;
notresocketfinale = accept(notresocket, //ancien descripteur
(struct sockaddr *)&addresseclient,// recuperation des info client
(int*)sizeof(struct sockaddr_in)); //taille de la structure sockaddr_in
2) Côté client :
1. L'ip du serveur :
Les adresse ip sont contenu dans des variable de type long.
long ipserveur = 0;
Pour transformer une chaîne de caractère en ip nous allons utiliser la fonction inet_addr()
Par exemple :
ipserveur = inet_addr("86.204.83.214");
Si votre ip est sous la forme d'un nom de domaine il faut utiliser la fonction gethostbyname().extern struct hostent * gethostbyname(const char * name);
Elle renvoie une structure de type hostent qui contient diverse information sur le nom de domaine.
struct hostent domaine; // on declare une structure hostend
domaine = *gethostbyname("samote.dyndns.org"); //on récupère les info du dns
L'ip du serveur est contenu dans le membres .h_addr_list
ipserveur = **domaine.h_addr_list;
2. sockaddr_in pour les infos du serveur :
Nous avons recuperé l'ip dans un long maintenant nous allons devoir crée une structure sockaddr_in :
struct sockaddr_in addresseserveur;
addresseserveur.sin_family = AF_INET; // AF_INET pour la famille
addresseserveur.sin_port = htons(8888); // meme port que pour le serveur
addresseserveur.sin_addr.s_addr = ipserveur; // on utilise la variable ip serveur
3. Creation du socket :
Nous allons passer a la création du socket :
int notresocketfinale = 0; // le descripteur de socket
notresocketfinale = socket(AF_INET, SOCK_STREAM, 0); // création du socket
4. La connection au serveur :
La connection au serveur de fait a l'aide de la fonction connect().
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
Elle doit être appelée pendant que le serveur fait appel a accept() :
connect(notresocketfinale, // le descripteur de socket
(struct sockaddr *)&addresseserveur, // les infos du serveur
sizeof(struct sockaddr)); // taille de la structure sockaddr_in
3) send() et recv() :
Nos deux ds sont désormais connectées, nous allons donc pouvoir utiliser send() et recv() pour transférer des données.
Notez que la ds serveur doit être allumer avant la ds client car connect() doit être appelé après accept(). Pour éviter se problème vous pouver faire appel a connect() lors de la pression d'une touche.
1. send() :
Voici le prototype de la fonction send :
int send(int sockfd, // le descripteur de socket
const void *msg, // un pointeur sur les données a envoyer
int len, // taille des données en octet
int flags); // mettre flag a 0
Il n'y a pas de type définie pour les données, on peut envoyer ce que l'on veut : variables de tout type, tableaux , structures...
2. recv() :
Voici le prototype de la fonction recv :
int recv(int sockfd, // le descripteur de socket
void *buf, // un pointeur sur le buffer
int len, // la taille maximal du buffer
unsigned int flags); // mettre flag a 0
Le buffer est la variable qui va recevoir les données.
La fonction recv() et une fonction bloquante, c'est a dire qu'elle bloque l'exécution du programme jusqu'à la réception d'un paquet.
Pour éviter cela on peut rendre le socket non bloquant :
u8 erreur = 1; // variable pour vérifier les erreurs
ioctl(notresocketfinale, // le descripteur de socket
FIONBIO,
&erreur); //la variable d'erreur
En mode non bloquant recv() renvoie -1 si il n'y a pas de paquet reçu.
4) Exemple d'utilisation :
Maintenant que les deux ds peuvent communiquer, nous allons réaliser la partie du programme qui affiche un texte lorsque l'écran de l'autre ds est touché.
Nous allons d'abord déclarer deux booléens :
bool donnesenvoyees = 0; // la variable que nous enverons avec send()
bool buffer = 0; // la variable qui va contenir les données reçues
Maintenant voici le code de la boucle principale :
while (1)
{
// donnesenvoyees vaut 1 si l'écran est touché
donnesenvoyees = Stylus.Held;
// on envoie la variable donnesenvoyees a l'autre ds
send(notresocketfinale, &donnesenvoyees, 1, 0);
// on reçois les données de l'autre ds, le buffer va être modifié
recv(notresocketfinale, &buffer, 1, 0);
//Si buffer vaut 1, l'écran de l'autre ds a été touché
if (buffer == 1)
{
// alors on affiche le texte
PA_OutputSimpleText (1, 16, 12, "Salut");
}
PA_WaitForVBL();
}
C'est la fin de ce tuto, j'espère que sa vous aura été utile.