3psilon website

slogan


Vous êtes ici : Accueil » Articles » Programmation

>>Les Sockets

25 juillet 2006
Auteur(e) : 

Qu’est-ce qu’un socket ?

Pour communiquer entre deux applications ou ordinateurs, il vous faut un téléphone, un socket. Un socket est attaché á un port ( une porte au sens imagé ). Vous ouvrez votre porte et attendez qu’un colis sois acheminé á celle-ci.

Une fois le colis reçu, vous pouvez soit envoyer un autre colis ou bien fermer la porte, le port.

Vous devez initialiser le socket, faire un lien avec le port, attendre pour un paquet, et fermer le socket. Pour avoir plus d’informations sur les protocoles de transfert TCP/IP ou bien sur les socket en général, voir la section Références.

Utilisation du socket

Créer un socket en C/C++ est relativement simple, contrairement á ce que la majorité du monde pensent.

La création d’un socket est faite par une chaîne de commandes. Pour commencer, il faut initialiser WSAStartup().

Un groupe de variables seront aussi nécéssaire pour faire cela. Bon, assez de bavardage et passons au code lui-même.


#include
#pragma comment(lib, "ws2_32.lib")

void main()
{
WSADATA WSAData;
WSAStartup(MAKEWORD(2,0), &WSAData);
}


winsock2.h, la librairie que vous vous servirez avec les sockets. Certaines personnes choisissent la librairie de la version 1, winsock.h. Dépendant de vos besoins. Si vous choisissez la version 1, prenez bien soin de choisir la librairie "wsock32.lib" au lieu de "ws2_32.lib".

WSADATA WSAData, l’initialisation d’une variable WSADATA. La variable va être utilisée pour le démarrage de WSAStartup().

Elle n’aura pas d’autre utilisation, généralement. WSAStartup(MAKEWORD(2,0), &WSAData), ce qui dis á votre ordinateur que vous allez utiliser des sockets.

Il y a deux paramètres á se rappeller, MAKEWORD(2,0) la version de winsock que vous désirez utiliser peut varier, dépendant des #include que vous aurez choisis.

Si vous avez choisi d’utiliser winsock 1 (winsock.h), remplacez le par MAKEWORD(1,0).

Le deuxieme paramètre á se rappeller, &WSAData, vraiment simple. Vous y mettez la variable de type WSADATA que vous avez définis plus haut. á la fin de votre programme, il est préférable de nettoyer votre WSA, en faisant WSACleanup() ;

Attention, ne pas faire de WSACleanup() tant que vous n’aurez pas terminé avec les sockets, sinon vous devrez initialiser WSAStartup() une deuxième fois.

Votre winsock est maintenant initialisé. Maintenant,il suffit de créer le socket lui-même.


SOCKET sock;
SOCKADDR_IN sin;

sin.sin_addr.s_addr = inet_addr("127.0.0.1");

sin.sin_family = AF_INET;
sin.sin_port = htons(4148);

sock = socket(AF_INET,SOCK_STREAM,0);
bind(sock, (SOCKADDR *)&sin, sizeof(sin));


Et voilá. Votre socket est initialisé. Notez par contre que celui-ci est initialisé pour vous connecter sur vous-même au port 4148. L’utilité est donc nulle, sauf si vous avez un serveur á ce port-ci.

SOCKET sock, initialisez une variable du type SOCKET qui sera utilisée pour définir le socket. SOCKADDR_IN sin, le struct du SOCKADDR contient les informations techniques du socket.

Par exemple, .sin_addr.s_addr, qui définis l’addresse du server. Si vous codez un serveur, vous n’avez pas á définir d’addresse, vous utiliseriez donc :


sin.sin_addr.s_addr = htonl(INADDR_ANY);


sin_family, la *famille* du socket, le type si on veut. Pour l’internet, les programmeurs utilisent généralement AF_INET.

Le dernier paramètre du struct á définir, sin_port. Le port sur lequel vous voulez vous connecter ou bien écouter. htons(4148) pourrait être remplacé par htons(23) si vous voulez le port telnet, etc...

socket(AF_INET, SOCK_STREAM, 0), la création du socket en tant que tel.

Le 1er paramètre est la famille du socket, comme vous l’avez configuré au par avant dans la structure du SOCKADDR_IN. AF_INET dans ce cas-ci.

La 2ième option, SOCK_STREAM, c’est le type de socket. Il existe aussi SOCK_DGRAM, dont je parlerai plus loin dans le texte. Les SOCK_STREAM ouvrent une conn entre les 2 ordinateurs directe et pourra ensuite envoyer les paquets que vous désirez, tandis que le SOCK_DGRAM envoie un paquet directement á la destination sans faire d’accept() ou de connect().

bind(sock, (SOCKADDR *)&sin, sizeof(sin)) ;, la commande qui va attacher votre socket directement au port et á l’adresse que vous avez défini dans le struct SOCKADDR_IN. Trois paramètres á retenir ici, sock, le socket que vous avez initialisé plut tôt.

La structure SOCKADDR_IN, la deuxième chose á retenir, la structure que vous aurez définis plus haut. Et finalement, la taille, sizeof(sin).

Maintenant votre chemin se divise en deux choix, le serveur ou le client. Si vous voulez faire un serveur. Vous devrez faire une boucle qui accept() les connections. Dans ce cas, c’est un petit peu plus compliqué.


listen(sock, 0);
int val = 0;
while(1)
{
val = accept(sock, (SOCKADDR *)&csin, sizeof(csin))
if(val != INVALID_SOCKET)
{
// Fonctions á éxécuter sur le socket.
}

}


Ok, procédons étape par étape. listen(sock, 0), listen va écouter le port sur le socket. La 1ere valeur, sock, est le socket sur lequel le listen() écoutera. La 2eme valeur, le BACKLOG.

Le nombre maximum de connections qui seront écoutées en même temps. La variable int val sera utilisée pour prendre la valeur de retour du accept() :


accept(sock, (SOCKADDR *)&sin, sizeof(csin))


La fonction qui va nous permettre d’accepter une connection.

Une autre fonction très simple, 1ere valeur : le socket. la 2eme valeur est votre SOCKADDR_IN que vous avez crée pour prendre les informations du client connecté sur votre serveur. Et finalement, la dernière valeur, sizeof(sin), la grosseur totale.

J’ai rajouté un if() pour vérifier si le socket est accepté, si quelqu’un est connecté, et si il l’est, il va effectuer les fonctions() que vous aurez mis au préallable dans le if(), par exemple un send().

Maintenant, passons au deuxième choix, le client. Rien de plus simple. Il n’y á qu’a faire un connect().


connect(sock, (SOCKADDR *)&sin, sizeof(sin))


connect, relativement semblable á accept(). Ces fonctions sont presque égales puisque la seule différence, le &sin. Vous mettez *VOTRE* SOCKADDR_IN au lieu de celui du client dans le accept().

Bravo, maintenant vous êtes connectés. Mais qu’est-ce que je vais faire a mon socket, maintenant que je suis connecté ?! Nous y arrivons.

Commandes reliées au sockets

Les commandes reliées au socketing les plus utilisées sont send(), recv(), sendto(), recvfrom(), closesocket(), shutdown(), getpeername(), gethostname().

send() Send, la commande pour envoyer une string au client ou au serveur. Tellement simple d’utilisation. send(socket, message, grosseur, 0) ; Le 1er paramètre étant le socket, le 2eme étant le message á envoyer.

Notez qu’un simple \n en socketing est \r\n, si vous ne faites pas de \r\n, le serveur/client ne le considérera pas comme un retour de chariot.

La grosseur, sizeof(message). Le dernier paramètre ne vous sera probablement jamais utile, vous marquerez donc 0. Exemple : send(sock, "Hello world !\r\n", 14, 0) ;

recv() Recv est une autre commande très simple. En fait elle est presque identique au send(). recv(socket, buffer, grosseur, 0) ; Les paramètres sont identiques au send() sauf qu’au lieu d’envoyer une string, vous le stockez dans une variable, le buffer. Exemple : recv(sock, buff, sizeof(buff), 0) ;

sendto() Avant de faire du SOCK_DGRAM, je suggère fortement de commencer par le SOCK_STREAM. C’est plus simple pour commencer, et de toutes fa ?ns c’est ce qui est le plus utilisé. L’art d’envoyer un paquet á un IP particulier, sans avoir á se connect()er. Initialisez votre WSAStartup() et vous êtes prêts á l’utiliser. Il est TRèS important de noter que lors de la création du socket(), il faut préciser SOCK_DGRAM et non pas SOCK_STREAM. sendto(socket, message, longueur, 0, sin, sizeof(sin)) ;.

Le premier paramètre, le socket lui-même. Ensuite, vous tapez votre message, la string á être envoyée, qui peut aussi bien être un buffer stocké dans une variable, suivi de la longueur du message.

Vous continuerez avec un nouveau SOCKADDR_IN qui aura les informations de la destination que vous aurez programmé á l’avance. Terminez cela avec un sizeof(sin). Remplacez la variable sin par celle du SOCKADDR_IN, bien sur.

recvfrom() La fonction recvfrom est presque identique á sendto(). Vous avez besoin d’utiliser SOCK_DGRAM lors de la création du socket(), comme pour le sendto(). recvfrom(socket, message, longueur, 0, sin, sizeof(sin)) ; Le sin sera celui du client qui vous aura envoyé un paquet. Notez que vous devrez configurer le sin comme si vous feriez un serveur régulier. Voir plus haut pour plus d’informations.

closesocket() L’art de fermer un socket d’une fa ?n facile et propre. Pour résumer cette fonction en une ligne, closesocket(socket). shutdown() C’est exactement comme un close(), mais vous avez beaucoup plus de contr ?e avec cette fonction. Par exemple, vous pouvez bloquer le flux re ?, envoyé ou les deux. Deux paramètres á retenir, le 1er, le socket. Et le deuxième, un int 0 a 3.

-  0 = Les recv ne seront plus acceptés
-  1 = Les send ne seront plus acceptés
-  2 = Ni les send, ni les recv ne seront acceptés, comme un close().

getpeername() Cette fonction, relativement utile, sert á savoir qui est connecté sur vous, des infos sur le client. Vous devez créer un SOCKADDR_IN pour stocker les informations, par contre. L’utilisation de cette fonction va comme-ci : getpeername(socket, sin, sizeof(sin)) ; Le sin étant le nouveau SOCKADDR_IN crée pour les besoins de la cause.

gethostname() Même principe que getpeername() en plus simple. gethostname(*hostname, sizeof(hostname)) ; *hostname étant un array stockant le *hostname* de votre propre machine. Exemples de codes Voici un client simple pour se connecter á irc. Notez que les recv() et les send() pour s’enregistrer et pouvoir l’utiliser comme un client ne sont pas incorporés.


#include
#pragma comment(lib, "ws2_32.lib")

void main()
{
WSADATA WSAData;
WSAStartup(MAKEWORD(2,0), &WSAData);

SOCKET sock;
SOCKADDR_IN sin;

char *buffer = new char[255];

/* Tout est configuré pour se
connecter sur IRC, haarlem, Undernet. */

sock = socket(AF_INET, SOCK_STREAM, 0);

sin.sin_addr.s_addr = inet_addr("62.250.14.6");
sin.sin_family = AF_INET;

sin.sin_port = htons(6667);

connect(sock, (SOCKADDR *)&sin, sizeof(sin));
recv(sock, buffer, sizeof(buffer), 0);

closesocket(sock);
WSACleanup();

}


Maintenant, voici un serveur simple qui envoie un Hello world ! a quiconque se connecte.


#include
#pragma comment(lib, "ws2_32.lib")


void main()
{
WSADATA WSAData;
WSAStartup(MAKEWORD(2,0), &WSAData);

SOCKET sock;

SOCKET csock;
SOCKADDR_IN sin;
SOCKADDR_IN csin;

sock = socket(AF_INET, SOCK_STREAM, 0);

sin.sin_addr.s_addr = INADDR_ANY;

sin.sin_family = AF_INET;
sin.sin_port = htons(23);

bind(sock, (SOCKADDR *)&sin, sizeof(sin));
listen(sock, 0);

while(1)
{
int sinsize = sizeof(csin);
if((csock = accept(sock, (SOCKADDR *)&csin,
&sinsize)) != INVALID_SOCKET)
{
send(csock, "Hello world!\r\n", 14, 0);
}
}
}



Ces code sources sont vraiment basiques, mais ils pourront toujours vous aider pour voir la structure d’un code C/C++ utilisant les socket.

Avec ces instruments et quelques autre documents sur les sockets, vous devriez être capable de maitriser les principes de bases et beaucoup plus.

Je vous suggère fortement de jeter un oeil sur la section document liés pour plus d’informations sur le sujet en général.

Document original par Walrus.

Vos commentaires sur cet article

  • Only for Men

    30 mai 2008, par Sonyxzas
    hi all ! After i’ve bought a viagra tabs at online shop http://www.edtabsonline.com/ My wife was surprised by me . We had a crazy sex last evening like when i was 21 years old. Now i have no any reason for dismays. I have happy life ! Now i am going to order a cialis ... because this pack are more effective than viagra. Only one question is bother me. Should I tell my wife about my secret ? May be this will offend her ?

  • Will You Give me an advice ?

    14 mai 2008, par Alexpolors
    hello everybody, i use the viagra pills at last time (about one year) but yesterday i found an article about cialis. and now i am going to buy cilais at http://www.edtabsonline.com/ and test this tablet. Someone took this tablet before ? Whats the effect ? Thanx

  • Seem

    15 avril 2005, par mellie
    Sympa le tutorial sur les sockets ! Un plus serait de faire le parallèle avec les sockets Unix/Linux.

Formuler un commentaire


3psilon (c) 2003

[W3C CSS Validator] [W3C XHTML Validator] [W3C WAI AAA]