Erstellen einen UDP-Server in C#

Saad Aslam 12 Oktober 2023
Erstellen einen UDP-Server in C#

Dieser Artikel zeigt, wie Sie einen einfachen UDP-Server in C# erstellen können.

Erstellen einen UDP-Server in C#

Kurz zum Hintergrund: Das UDP-Protokoll muss keine Verbindung mit dem Client aufbauen. Die Daten werden einfach übertragen, ohne zu authentifizieren, ob der Client sie erhalten hat oder nicht.

Diese Art von Protokoll wird normalerweise zum Senden der Daten verwendet. Da UDP verbindungslos ist, muss ein Listener nicht online sein, um die Nachricht zu empfangen.

Um ein Datagramm mit UDP zu übertragen, müssen Sie die Netzwerkadresse des Netzwerkgeräts kennen, das den Dienst hostet, sowie die UDP-Portnummer des Dienstes. Portnummern für beliebte Dienste werden von der Internet Assigned Numbers Authority (IANA) definiert; Der Bereich der Portnummern reicht von 1.024 bis 65.535 und kann Diensten zugewiesen werden, die nicht auf der IANA-Liste stehen.

In IP-basierten Netzwerken werden spezielle Netzwerkadressen verwendet, um UDP-Broadcast-Nachrichten zu verarbeiten. Die folgende Erläuterung verwendet die IP-Adressenfamilie Version 4 des Internets als Beispiel.

Durch Setzen aller Bits der Host-Identifikation können Rundsendungen an bestimmte Teile eines Netzwerks gerichtet werden. Verwenden Sie die Adresse 192.168.1.255, um an alle Hosts im Netzwerk mit IP-Adressen zu senden, die mit 192.168.1 beginnen.

Wir sind jetzt bereit, einen Socket zu bauen oder zu erstellen, unser UDP-Protokoll einzurichten und die Kommunikation sofort zu starten.

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

Dies wären die Bibliotheken, die zum Einrichten des Servers verwendet werden. Diese Bibliotheken unterstützen alle grundlegenden Funktionen im Zusammenhang mit Netzwerken, wie z. B. das Erstellen von Sockets, die Handhabung der IPV4-Adressen und vieles mehr.

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);
  }
}

Die Zeile int recv erstellt eine recv-Variable vom Typ Integer, die die Anzahl der Bytes der String-Nachricht enthält, die der Client erhalten hat.

Die byte[] data = new byte[1024]; line wird verwendet, um ein Array namens data mit Bytegröße für jede Zelle mit 1024 Zellen zu erstellen, auch Arraygröße genannt. Dieses Array wird dynamisch in einem Heap erstellt.

Der IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050); line teilt dem mit, eine ipep-Variable für den Socket zu erstellen. Die darin übergebenen Informationen geben an, welche Art von Socket verwendet werden soll.

Die Klasse IPEndPoint repräsentiert einen Netzwerkendpunkt mit IP-Adresse und Portnummer; Der Client benötigt diese Konfigurationsinformationen, um sich mit unserem Dienst zu verbinden. Das übergebene Argument IPAddress.Any sagt aus, dass der Server sich mit jeder IP-Adresse mit der Portnummer 9050 verbinden kann; die Variable ipep wird ebenfalls dynamisch erstellt.

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

Diese Zeile erstellt eine newsock-Variable, einen Socket für uns, über den wir kommunizieren werden. Die darin übergebenen Argumente geben an, welche Art von Socket wir erstellen möchten.

Die AddressFamily.InterNetwork sagt uns, dass wir die lokalen IP-Adressen wollen. Das Argument SocketType.Dgram besagt, dass die Daten in Datagrammen statt in Paketen fliessen sollen.

Und schließlich gibt das Argument ProtocolType.Udp den Protokolltyp des Sockets an, den wir verwenden werden. Jetzt wird unser Socket erstellt.

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

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

Bis jetzt hatten wir unseren einen Endpunkt im Netzwerk und einen Socket erstellt, über den wir kommunizieren werden, newsock.Bind(ipep); line hilft uns nun, unseren Endpunkt an den Socket zu binden.

ipep ist die Variable, die die Informationen über unseren Endpunkt enthält und in der bind()-Funktion unseres newsock-Objekts übergeben wird.

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

Diese Zeile gibt auf dem Bildschirm aus, dass der Server darauf wartet, dass der Client eine Nachricht sendet. Wir müssen einen weiteren Endpunkt für den Absender erstellen, der versucht, mit dem Server zu kommunizieren.

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

Diese Zeile erstellt einen weiteren Endpunkt, und die Variable heißt sender. Das Argument, das in seiner IPAddress.Any übergeben wird, sagt aus, dass wir eine beliebige IP-Adresse erwarten, und 0 bedeutet, dass es sich um einen Platzhalter für die Portnummer handelt, und das System sollte jeden geeigneten Port sehen und finden, der uns diese zuweist.

Der EndPoint Remote = (EndPoint)(sender); line wird verwendet, um die IP-Adresse des Absenders zu finden und in der Variable remote zu speichern.

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

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

Die Variable recv, die wir zu Beginn unseres Programms erstellt haben, wird nun in Zeile recv = newsock.ReceiveFrom(data, ref Remote); verwendet. Wir verwenden die Funktion Receive() des zuvor erstellten Sockets newsock und erhalten aktuell alle Daten, die wir zu diesem Zeitpunkt im Socket haben.

Die Argumente, die die Funktion Receive() übergeben, sagen, wo die Daten gespeichert werden sollen und welche Daten gespeichert werden sollen oder erwartet werden. Das Argument data ist das Byte-Größen-Array, das übergeben wird, und die Daten werden in das Daten-Array geschrieben.

Das Argument ref Remote teilt mit, dass diese IP-Adresse die Daten gesendet hat, und die Funktion gibt die Anzahl der von diesem Socket abgerufenen Bytes zurück und speichert sie in der Variablen recv.

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

Diese Zeile schreibt die IP-Adresse des Clients auf den Bildschirm, der die Daten über den Socket gesendet hat. Das übergebene Argument Remote.ToString() konvertiert die Dezimalzahlen in die ASCII-Zeichen, und die remote-Variable war der zweite Endpunkt, der auf den Client verweist.

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

Diese Zeile schreibt die eigentlichen Daten auf den Bildschirm. Die über den Socket gesendeten Daten liegen in Rohform vor und sollten zum Lesen in ASCII-Zeichen konvertiert werden.

Die Zeile Encoding.ASCII.GetString(data, 0, recv) übernimmt die Daten aus der Variablen data, die als Argument übergeben wird, und das Argument recv (enthält die Anzahl der vom Client gesendeten Bytes) teilt dies mit diese vielen Bytes aus der Variablen data auf den Bildschirm zu schreiben.

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

Der String welcome = "Welcome to my test server"; line initialisieren Sie die String-Variable welcome mit dem Text Welcome to my test server.

Die data = Encoding.ASCII.GetBytes(welcome); line nimmt die welcome-Variable als Argument in der Encoding.ASCII.GetBytes()-Funktion und konvertiert sie in die Rohform, sodass sie bereit ist, durch den Socket am anderen Ende gesendet zu werden.

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

Diese Zeile sendet die Daten durch unseren zuvor erstellten Socket newsock und verwendet die Funktion Send(). Die Argumente, die es braucht, sind: die data-Variable, die die Rohform der zu sendenden Daten enthält, das data.Length-Argument, das angibt, wie viele Bytes auf den Socket geschrieben werden sollen, da die Länge der Daten der Anzahl der Bytes entspricht , das Argument SocketFlags.None, das uns sagt, dass wir alle Flags auf Null halten sollen, die Flags sind Indikatoren und jedes Flag hat seine Bedeutung.

Das Variablenargument Remote teilt uns mit, an welchen Client wir die Daten senden möchten, da die Variable Remote die IP-Adresse und die Portnummer des Clients speichert.

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);
}

Die while(true)-Zeile sagt aus, dass es sich um eine Endlosschleife handelt und dass alle ihre Anweisungen unendlich laufen. Die data = new byte[1024]; line erstellt bei jeder Ausführung ein neues Byte-Array der Länge 1024.

Die recv = newsock.ReceiveFrom(data, ref Remote); line empfängt die Daten vom Client und speichert sie im Datenarray.

Die Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv)); schreibt die Daten auf den Bildschirm.

Das newsock.SendTo(data, recv, SocketFlags.None, Remote); line sendet dieselben Daten an den Client zurück, die der Server von ihr erhalten hat.

Danach hält der Server wieder an und wartet auf den Client, und alles, was der Client an den Server sendet, antwortet mit derselben Nachricht. Dieser Server wird niemals beendet, es sei denn, er stürzt ab oder der Benutzer stoppt ihn manuell.

Nachdem wir nun gelernt haben, wie man einen UDP-Server in C# und seine grundlegenden Funktionen erstellt, können wir weitere Funktionen hinzufügen und einen Server gemäß unseren Anforderungen erstellen.

Vollständiger Quellcode:

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);
    }
  }
}
Autor: 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

Verwandter Artikel - Csharp Server