Créer un serveur UDP en C#

Saad Aslam 12 octobre 2023
Créer un serveur UDP en C#

Cet article vous montrera comment vous pouvez créer un serveur UDP simple en C#.

Créer un serveur UDP en C#

Pour un bref aperçu, le protocole UDP n’a pas besoin d’établir une connexion avec le client. Les données sont simplement transmises sans s’authentifier si le client les a reçues ou non.

Ce type de protocole est généralement utilisé pour la diffusion des données. Comme UDP est sans connexion, un auditeur n’a pas besoin d’être en ligne pour recevoir le message.

Pour transmettre un datagramme avec UDP, vous devez connaître l’adresse réseau du périphérique réseau qui héberge le service et le numéro de port UDP du service. Les numéros de port pour les services populaires sont définis par l’Internet Assigned Numbers Authority (IANA); la plage de numéros de port va de 1 024 à 65 535 et peut être attribuée à des services qui ne figurent pas sur la liste IANA.

Sur les réseaux IP, des adresses réseau spéciales sont utilisées pour gérer les messages de diffusion UDP. L’explication suivante utilise la famille d’adresses IP version 4 d’Internet comme exemple.

En réglant tous les bits de l’identification de l’hôte, les diffusions peuvent être dirigées vers des parties spécifiées d’un réseau. Utilisez l’adresse 192.168.1.255 pour diffuser vers tous les hôtes du réseau dont les adresses IP commencent par 192.168.1.

Nous sommes maintenant prêts à construire ou à créer un socket, à configurer notre protocole UDP et à démarrer la communication immédiatement.

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

Il s’agirait des bibliothèques utilisées pour configurer le serveur. Ces bibliothèques prennent en charge toutes les fonctionnalités de base liées au réseau, telles que la création de sockets, la gestion des adresses IPV4, etc.

public class SimpleUdpSrvr {
  public static void Main() {
    int recv;
    byte[] data = new byte[1024];
    IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);
    Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  }
}

La ligne int recv crée une variable recv de type entier qui contient le nombre d’octets du message de chaîne que le client a reçu.

La ligne byte[] data = new byte[1024]; est utilisée pour créer un tableau nommé data de taille en octets pour chaque cellule avec 1024 cellules, également appelé taille de tableau. Ce tableau est créé dynamiquement dans un tas.

Le IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050); indique que créer une variable ipep pour le socket. Les informations qui y transitent indiquent le type de socket à utiliser.

La classe IPEndPoint représente un point de terminaison du réseau avec une adresse IP et un numéro de port ; le client a besoin de ces informations de configuration pour se connecter à notre service. L’argument IPAddress.Any transmis indique que le serveur peut se connecter avec n’importe quelle adresse IP au numéro de port 9050; la variable ipep est également créée dynamiquement.

Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

Cette ligne crée une variable newsock, une socket pour nous à travers laquelle nous allons communiquer. Les arguments qui y passent indiquent le type de socket que nous voulons créer.

Le AddressFamily.InterNetwork nous dit que nous voulons les adresses IP locales. L’argument SocketType.Dgram indique que les données doivent circuler dans des datagrammes au lieu de paquets.

Et enfin, l’argument ProtocolType.Udp indique le type de protocole du socket que nous allons utiliser. Maintenant, notre socket est créé.

newsock.Bind(ipep);
Console.WriteLine("Waiting for a client...");

IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint Remote = (EndPoint)(sender);

Jusqu’à présent, nous avions créé notre seul point de terminaison dans le réseau, et un socket à travers lequel nous communiquerons, newsock.Bind(ipep); La ligne va maintenant nous aider à lier notre point de terminaison au socket.

ipep est la variable qui contient les informations sur notre point de terminaison et est passée dans la fonction bind() de notre objet newsock.

Console.WriteLine("Waiting for a client...");

Cette ligne imprime à l’écran que le serveur attend que le client envoie un message. Nous devons créer un autre point de terminaison pour l’expéditeur qui tentera de communiquer avec le serveur.

IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);

Cette ligne crée un autre point de terminaison, et la variable s’appelle sender. L’argument passé dans son IPAddress.Any indique que nous attendons n’importe quelle adresse IP, et 0 signifie qu’il s’agit d’un joker pour le numéro de port, et le système devrait voir et trouver tout port approprié qui nous l’attribue.

Le EndPoint Remote = (EndPoint)(sender); permet de trouver l’adresse IP de l’expéditeur et de la stocker dans la variable remote.

recv = newsock.ReceiveFrom(data, ref Remote);

Console.WriteLine("Message received from {0}:", Remote.ToString());
Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));

La variable recv que nous avons créée au début de notre programme est maintenant utilisée dans le recv = newsock.ReceiveFrom(data, ref Remote); ligne. Nous utilisons la fonction Receive() du socket que nous avons créé précédemment, newsock, et recevons actuellement toutes les données que nous avons dans le socket à ce moment-là.

Les arguments passant la fonction Receive() indiquent où stocker les données et qui doit être stocké ou est attendu. L’argument data est le tableau de taille d’octets passé, et les données seront écrites dans un tableau de données.

L’argument ref Remote indique que cette adresse IP a envoyé les données, et la fonction renverra le nombre d’octets extraits de cette socket et le stockera dans la variable recv.

Console.WriteLine("Message received from {0}:", Remote.ToString());

Cette ligne écrit à l’écran l’adresse IP du client qui a envoyé les données via le socket. L’argument passé Remote.ToString() convertit les nombres décimaux en caractères ASCII, et la variable remote était le deuxième point de terminaison faisant référence au client.

Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));

Cette ligne écrit les données réelles à l’écran. Les données envoyées via le socket sont sous forme brute et doivent être converties en caractères ASCII pour être lues.

La ligne Encoding.ASCII.GetString(data, 0, recv) prend les données de la variable data qui est passée en argument, et l’argument recv (contient le nombre d’octets que le client a envoyé) indique que pour écrire ces nombreux octets à partir de la variable data à l’écran.

string welcome = "Welcome to my test server";
data = Encoding.ASCII.GetBytes(welcome);
newsock.SendTo(data, data.Length, SocketFlags.None, Remote);

La ligne string welcome = "Welcome to my test server"; initialise la variable welcome string avec le texte Welcome to my test server.

Le data = Encoding.ASCII.GetBytes(welcome); prend la variable welcome comme argument dans la fonction Encoding.ASCII.GetBytes() et la convertit au format brut, afin qu’elle soit prête à être envoyée via le socket à l’autre extrémité.

newsock.SendTo(data, data.Length, SocketFlags.None, Remote);

Cette ligne envoie les données via notre socket newsock précédemment créé et utilise la fonction Send(). Les arguments qu’il prend sont : la variable data contenant la forme brute des données à envoyer, l’argument data.Length indiquant le nombre d’octets à écrire sur la socket car la longueur des données est équivalente au nombre d’octets , l’argument SocketFlags.None nous indiquant de garder tous les drapeaux à zéro, les drapeaux sont des indicateurs, et chaque drapeau a sa signification.

L’argument variable Remote nous renseigne sur le client auquel nous voulons envoyer les données car la variable Remote stocke l’adresse IP et le numéro de port du client.

while (true) {
  data = new byte[1024];
  recv = newsock.ReceiveFrom(data, ref Remote);

  Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
  newsock.SendTo(data, recv, SocketFlags.None, Remote);
}

La ligne while(true) indique qu’il s’agit d’une boucle infinie et que toutes ses instructions s’exécuteront à l’infini. La ligne data = new byte[1024]; crée un nouveau tableau de taille d’octets de longueur 1024 chaque fois qu’il est exécuté.

Le recv = newsock.ReceiveFrom(data, ref Remote); line reçoit les données du client et les enregistre dans le tableau de données.

La Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv)); écrit les données sur l’écran.

Le newsock.SendTo(data, recv, SocketFlags.None, Remote); renvoie au client les mêmes données que celles que le serveur a reçues de lui.

Après cela, le serveur s’arrêtera à nouveau et attendra le client, et tout ce que le client envoie au serveur répondra avec le même message. Ce serveur ne se terminera jamais à moins qu’il ne tombe en panne ou que l’utilisateur ne l’arrête manuellement.

Maintenant que nous avons appris à créer un serveur UDP en C# et ses fonctionnalités de base, nous pouvons ajouter plus de fonctionnalités et créer un serveur selon nos besoins.

Code source complet :

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class SimpleUdpSrvr {
  public static void Main() {
    int recv;
    byte[] data = new byte[1024];
    IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);

    Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

    newsock.Bind(ipep);
    Console.WriteLine("Waiting for a client...");

    IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
    EndPoint Remote = (EndPoint)(sender);

    recv = newsock.ReceiveFrom(data, ref Remote);

    Console.WriteLine("Message received from {0}:", Remote.ToString());
    Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));

    string welcome = "Welcome to my test server";
    data = Encoding.ASCII.GetBytes(welcome);
    newsock.SendTo(data, data.Length, SocketFlags.None, Remote);
    while (true) {
      data = new byte[1024];
      recv = newsock.ReceiveFrom(data, ref Remote);

      Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
      newsock.SendTo(data, recv, SocketFlags.None, Remote);
    }
  }
}
Auteur: Saad Aslam
Saad Aslam avatar Saad Aslam avatar

I'm a Flutter application developer with 1 year of professional experience in the field. I've created applications for both, android and iOS using AWS and Firebase, as the backend. I've written articles relating to the theoretical and problem-solving aspects of C, C++, and C#. I'm currently enrolled in an undergraduate program for Information Technology.

LinkedIn