Utilisation des sockets côté serveur en mode datagramme

En langage C :

Après avoir créé le socket, il va falloir indiquer le port sur lequel on écoutera l'arrivée des datagrammes des clients.

Pour cela, on utilisera la fonction bind en lui passant 3 paramètres :

Il va donc falloir déclarer une variante de la structure sockaddr correspondant à AF_INET. Il s'agit du type struct sockaddr_in. On commencera par mettre à zéro le contenu de cette structure via la fonction bzero de string.h, puis on affectera, au premier champ nommé ici sin_family, la valeur AF_INET.

struct sockaddr_in	adr_srv;

bzero(&adr_srv, sizeof(adr_srv));
adr_srv.sin_family = AF_INET;
	

Il faut ensuite remplir, dans la structure, le champ sin_port avec le numéro de son port TCP sur laquelle le serveur écoute et éventuellement le champ sin_addr avec l'adresse IPv4. (On peut également laisser à zéro l'adresse IPv4 pour écouter sur toutes les interfaces.)

inet_aton("127.0.0.1", &adr_srv.sin_addr);
adr_srv.sin_port = htons(7);
	

Ayant ainsi précisé l'adresse 127.0.0.1 et le port 7, il ne reste plus qu'à appeler la fonction bind.

bind(fd_srv, (struct sockaddr *) &adr_srv, sizeof(adr_srv));
	

Il faut ensuite attendre, dans une boucle while, l'arrivée d'un datagramme via la fonction recvfrom qui nécessite 6 paramètres :

La fonction retourne le nombre d'octets reçus dans le buffer.

struct sockaddr_in adr_cli;
socklen_t adr_cli_len;

adr_cli_len = sizeof(adr_cli);
n = recvfrom(fd_srv, &buffer, sizeof(buffer), MSG_WAITALL, (struct sockaddr *) &adr_cli, &adr_cli_len);
	

Exemple :

#include <stdio.h>
#include <stdlib.h>

#include <sys/types.h>
#include <netdb.h>
#include <sys/socket.h>

#include <string.h>		// pour la fonction bzero
#include <arpa/inet.h>	// pour la fonction inet_addr

int main()
{
	int fd_srv;
	struct sockaddr_in adr_srv, adr_cli;
	socklen_t adr_cli_len;
	int err;

	int n;
	char buffer[1024];

	fd_srv = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (fd_srv<0) {
		printf("Erreur de creation de la socket !\n");
		exit(1);
	}

	bzero(&addr, sizeof(adr_srv));
	addr.sin_family = AF_INET;
	err = inet_aton("127.0.0.1", &adr_srv.sin_addr);
	if (err == 0) {
		printf("Adresse IPv4 invalide !\n");
		exit(1);
	}
	addr.sin_port = htons(8080);
	err = bind(fd_srv, (struct sockaddr *) &adr_srv, sizeof(adr_srv));
	if (err != 0) {
		printf("Erreur d'accès au port serveur !\n");
		exit(1);
	}

	while(1) {
		adr_cli_len = sizeof(adr_cli);
		n = recvfrom(fd_srv, &buffer, sizeof(buffer), MSG_WAITALL, (struct sockaddr *) &adr_cli, &adr_cli_len);
		printf("Message de taille %d octets reçu depuis %s:%d\n", n, inet_ntoa(adr_cli.sin_addr), ntohs(adr_cli.sin_port));
	}
	return 0;
}
	

PHP et Python :

Dans les langages comme PHP ou Python, il existe des bibliothèques faisant l'interface avec les fonctions systèmes.

PHP

Le code de l'exemple écrit en C devient en PHP :

$sock_srv = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($sock_srv== false) die("Erreur de creation de la socket !\n");
$err = socket_bind($sock_srv, '127.0.0.1', 8080);
if ($err == false) die("Erreur d'accès au port serveur !\n");
echo "Serveur lancé !\n";
while (true) {
	$from = '';
	$port = 0;
	socket_recvfrom($sock_srv, $buf, 1024, MSG_WAITALL, $from, $port);
	echo "message de taille ",strlen($buf)," octets reçu depuis ",$from,":",$port,"\n";
}
	

Python

Le code de l'exemple écrit en C devient en Python :

import socket

try:
	sock_srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	sock_srv.bind(('127.0.0.1', 8080))
except socket.error:
	print("Erreur de lancement du serveur !")
	exit()
print("Serveur lancé !")
while True :
	try :
		buffer, adresse = sock_srv.recvfrom(1024)
		ip, port = adresse
		print("message de taille",len(buffer),"octets reçu depuis",ip+":"+str(port))
	except socket.error :
		print("Erreur sur la lecture d'un datagramme !")
		exit()