Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
UDP Daten auf selben Port empfangen und senden
C0dR
myCSharp.de - Member



Dabei seit:
Beiträge: 4

Themenstarter:

UDP Daten auf selben Port empfangen und senden

beantworten | zitieren | melden

Hallo!

Ich habe vor einen serverlosen Chat auf UDP basis zu programmieren. Jetzt habe ich aber das Problem dass manchmal Nachrichten einfach nicht ankommen. Manchmal gehts, manchmal nicht. Manchmal hilft ein reconnect, aber nicht immer. Ich weis einfach nicht mehr weiter....

Ich poste mal den relevanten Code, vielleicht habe ich auch einfach nur einen logikfehler gemacht?


//Usings habe ich hier rausgenommen

namespace UDPChat
{
    public class ConnHandler
    {
        public UdpClient udpResponse;
         UdpClient udpClient;
        IPEndPoint RemoteIpEndPoint;
        public bool sending = false;
        int port = 0;

        public ConnHandler(int pPort)
        {
            try
            {
                port = pPort;
                RemoteIpEndPoint = new IPEndPoint(IPAddress.Any,port);
            }
            catch (Exception ex)
            {
                if (ex.Message == "Normalerweise darf jede Socketadresse (Protokoll, Netzwerkadresse oder Anschluss) nur jeweils einmal verwendet werden")
                {
                    MessageBox.Show(text: "Fehler beim Verbinden an Port " + port + "!\nMöglicherweise wird der Port bereits von einem anderen Programm benutzt.", icon: MessageBoxIcon.Error,buttons:MessageBoxButtons.OK, caption: "Fehler beim Verbinden!");
                }
            }
        }

        public void send(Byte[] pData)
        {
            sending = true;
            if (udpResponse != null)
                udpResponse.Close();
            udpClient = new UdpClient(port);
            udpClient.Connect(IPAddress.Broadcast, port);
            udpClient.Send(pData, pData.Length);
            udpClient.Close();
            sending = false;
            udpResponse = new UdpClient(port);
        }

        public string receive()
        {
            try
            {
                Byte[] receiveBytes = {Convert.ToByte(0)};
                receiveBytes = udpResponse.Receive(ref RemoteIpEndPoint);
                return Encoding.ASCII.GetString(receiveBytes);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public void close()
        {
            udpClient.Close();
        }
    }
}


Aufgerufen wird das ganze nach dem Eingeben eines textes in der textbox, genauer gesagt nach dem drücken der Enter Taste:


private void CheckKeys(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)13)
            {
                if (txtInput.Text != "\n")
                {
                    if (connection != null)
                    {
                        workerThread.Abort();
                        connection.send(Encoding.ASCII.GetBytes(txtInput.Text));
                        writeNewLine(txtInput.Text);
                        workerThread = new Thread(workerObject.listenMessages);
                    }
                    else
                        txtChatlog.Text = "Sie müssen zuerst eine Verbindung herstellen!";
                }
                txtInput.Text = "";

            }
        }


Der WorkerThread ist der der die ganze Zeit wartet bis eine Nachricht ankommt:


 public class messageHandler
    {
        ConnHandler pConnection;
        Form1 window;

        public messageHandler(ConnHandler pCon, Form1 pWindow)
        {
            this.pConnection = pCon;
            this.window = pWindow;
        }
        public void listenMessages()
        {
            while (!_shouldStop)
            {
                if(!pConnection.sending)
                    window.writeNewLine(pConnection.receive());
                Thread.Sleep(500);
            }
            Console.WriteLine("worker thread: terminating gracefully.");
        }
        public void RequestStop()
        {
            _shouldStop = true;
        }
        private volatile bool _shouldStop;
    }

Ich vermute dass der Fehler daher kommt, dass manchmal beim emfangen der Thread beendet wird, ohne dass die Daten richtig angekommen sind? Wie könnte ich das besser lösen oder ist das auf diese Art gar nicht möglich?

Ich hoffe ihr versteht meinen (nicht ganz ordentlichen) Code und mein problem. Ich weis einfach nicht mehr weiter.. :<


lg
C0dR
private Nachricht | Beiträge des Benutzers
ujr
myCSharp.de - Experte



Dabei seit:
Beiträge: 1.688

beantworten | zitieren | melden

Hallo,
Zitat von C0dR
Manchmal hilft ein reconnect

was ist ein "reconnect"? UDP ist verbindungslos.

Versuch's mal ohne den .Connect-Aufruf.
private Nachricht | Beiträge des Benutzers
MHI
myCSharp.de - Member



Dabei seit:
Beiträge: 8

beantworten | zitieren | melden

Wie schon im anderen Thread gesagt, sich einfach mal Informieren wie UDP aufgebaut ist und wie es über die IP-Ebene transportiert wird.
Und auch abermals der Hinweis, den Header selbst zusammen zu schrauben und pakete auf IP-Ebene raushauen (SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, true);) tut's, ohne das man das von MS im .Net Framework verwurstete UDPSocket nutzen muß
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von MHI am .
private Nachricht | Beiträge des Benutzers
DaMoe80
myCSharp.de - Member



Dabei seit:
Beiträge: 500

beantworten | zitieren | melden

Hi!

Ich habe den Eintrag nur ueberflogen, und mir hat sich gleich die Frage gestellt, ob Du Dir dessen im klaren bist, dass UDP kein zuverlaessiges Protokoll ist, d.h. Du Nachrichten wohl verlieren kannst. Eine fehlerhafte Uebertragung kann man mit einer sogenannten Integritaetspruefung erkennen. Kann es nicht sein, dass Dein Problem in UDP begruendet ist, das es keine Ubertragungsgarantie gewaehrleistet?

Gruss,
Moe
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von DaMoe80 am .
private Nachricht | Beiträge des Benutzers
PPK
myCSharp.de - Member



Dabei seit:
Beiträge: 157

beantworten | zitieren | melden

Wieso schließt du überhaubt dein UDPClient?
Und die Connect würde ich auch raus nehmen und per SendTo senden.
Wieso benutzt du eigentlich UDP und nicht TCP?
private Nachricht | Beiträge des Benutzers
C0dR
myCSharp.de - Member



Dabei seit:
Beiträge: 4

Themenstarter:

beantworten | zitieren | melden

Zitat von ujr
was ist ein "reconnect"? UDP ist verbindungslos.

Versuch's mal ohne den .Connect-Aufruf.

Mit reconnect meine ich den Lauschvorgang abzubrechen und neuzustarten (kurz gesagt Programm beenden und neu aufrufen).

Zitat von PPK
Wieso schließt du überhaubt dein UDPClient?
Und die Connect würde ich auch raus nehmen und per SendTo senden.
Wieso benutzt du eigentlich UDP und nicht TCP?

Wie genau meinst du das mit sendTo? Ich benutze UDP weil ich einen Serverlosen chat basteln wollte und da ist doch TCP ein wenig ungeeignet oder irre ich mich?


Ich hatte eigentlich gehofft dass UDP nicht sooo viel Pakete verliert (1, 2 würde ich noch verkraften) aber wenn es doch tatsächlich so drastisch ist wird das wohl doch nichts aus dem Serverlosen chat. (eigentlich dachte ich dass ich einfach nur einen Fehler in meinem Codeaufbau gemacht habe und deshalb die Pakete verloren gehen :/ )


//EDIT: ok, ihr habt mich doch auf die richtige Spur gebracht. ICh hab es doch hinbekommen. Die Lösung war, das connect komplett weg zu lassen und es direkt über ein IPEndPoint zu machen. So musste ich auch nicht jedes mal .close() ausführen und es kommen alle Daten an!

Meine Klasse sieht jetzt so aus:


 public class ConnHandler
    {
        public UdpClient udpResponse;
        UdpClient udpClient;
        IPEndPoint RemoteIpEndPoint;
        IPEndPoint sendIpEndPoint;
        int port = 0;

        public ConnHandler(int pPort)
        {
            try
            {
                port = pPort;
                RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, port);
                sendIpEndPoint = new IPEndPoint(IPAddress.Broadcast, port);
                udpClient = new UdpClient();
                udpResponse = new UdpClient(port);
            }
            catch (Exception ex)
            {
                if (ex.Message == "Normalerweise darf jede Socketadresse (Protokoll, Netzwerkadresse oder Anschluss) nur jeweils einmal verwendet werden")
                {
                    MessageBox.Show(text: "Fehler beim Verbinden an Port " + port + "!\nMöglicherweise wird der Port bereits von einem anderen Programm benutzt.", icon: MessageBoxIcon.Error, buttons: MessageBoxButtons.OK, caption: "Fehler beim Verbinden!");
                }
            }
        }

        public void send(Byte[] pData)
        {
            udpClient.Send(pData, pData.Length,sendIpEndPoint);
        }

        public string receive()
        {
            try
            {
                Byte[] receiveBytes = { Convert.ToByte(0) };
                receiveBytes = udpResponse.Receive(ref RemoteIpEndPoint);
                return Encoding.Unicode.GetString(receiveBytes);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public void close()
        {
            if(udpClient != null) udpClient.Close();
            if (udpResponse != null) { udpResponse.Close();}
        }
    }

Jetzt funktioniert alles! Danke für eure Unterstützung, ihr habt mich auf den richtigen Pfad gebracht!
Wer den chat mal sehen will soll mir ne PN schreiben ;)
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von C0dR am .
private Nachricht | Beiträge des Benutzers
ujr
myCSharp.de - Experte



Dabei seit:
Beiträge: 1.688

beantworten | zitieren | melden

Zitat von C0dR


            catch (Exception ex)
            {
                if (ex.Message == "Normalerweise darf jede Socketadresse (Protokoll, Netzwerkadresse oder Anschluss) nur jeweils einmal verwendet werden")
...
            catch (Exception ex)
            {
                throw ex;
            }

Du solltest dringend über Exceptions nachlesen. Besonders der Textvergleich ist unsinnig - was passiert, wenn Microsoft die Fehlermeldung anpasst? oder bei einer komplett anderen Sprache? Dafür gibt es spezialisierte Exceptions mit besonderen Parametern.
private Nachricht | Beiträge des Benutzers
C0dR
myCSharp.de - Member



Dabei seit:
Beiträge: 4

Themenstarter:

beantworten | zitieren | melden

Mh da hast du recht. Hab es rausgenommen. Die Meldung wird sowieso nicht mehr benötigt. Aber danke für den Hinweis!
private Nachricht | Beiträge des Benutzers
progi123
myCSharp.de - Member

Avatar #avatar-3317.gif


Dabei seit:
Beiträge: 71
Herkunft: Süddeutschland

beantworten | zitieren | melden

Mein Provider vergisst gerne das ein oder andere UDP-Paket zuverlässig zuzustellen. Muss also nicht an der Software liegen..
private Nachricht | Beiträge des Benutzers
DaMoe80
myCSharp.de - Member



Dabei seit:
Beiträge: 500

beantworten | zitieren | melden

@progi123:
Zitat
...mir hat sich gleich die Frage gestellt, ob Du Dir dessen im klaren bist, dass UDP kein zuverlaessiges Protokoll ist,....
private Nachricht | Beiträge des Benutzers
mogel
myCSharp.de - Member

Avatar #avatar-3347.jpg


Dabei seit:
Beiträge: 156

beantworten | zitieren | melden

Zitat von C0dR
Wie genau meinst du das mit sendTo? Ich benutze UDP weil ich einen Serverlosen chat basteln wollte und da ist doch TCP ein wenig ungeeignet oder irre ich mich?
wenn Du uns jetzt verrätst wie einer Serverloser-Chat funktionieren soll, dann darfst Du weiterhin mit UDP basteln
Zitat von Wikipedia
Der Begriff Server (engl. für Diener) bezeichnet entweder eine Software (Programm) im Rahmen des Client-Server-Modells oder eine Hardware[1] [2] (Computer), auf der diese Software (Programm) im Rahmen dieses Konzepts abläuft.
  • Ein Server (Software) ist ein Programm, das mit einem anderen Programm, dem Client (englisch für Kunde), kommuniziert, um ihm Zugang zu speziellen Dienstleistungen (genannt Dienste) zu verschaffen.
  • Ein Server (Hardware) ist ein Computer, auf dem ein oder mehrere Server (Software) laufen.
ich konnte da noch nicht lesen das ein Server UDP oder TCP verwenden muss ... Du hast immer einen Server und immer mind. einen Client (soviel zum Thema "Serverloser Chat")
Zitat von C0dR
Jetzt habe ich aber das Problem dass manchmal Nachrichten einfach nicht ankommen. Manchmal gehts, manchmal nicht.
ja - so ist das Lotteriespiel mit UDP :)

hand, mogel

BTW: nimm bitte TCP zur Kommunikation zwischen den Clients - das macht Dir Dein Leben um einiges leichter
private Nachricht | Beiträge des Benutzers
C0dR
myCSharp.de - Member



Dabei seit:
Beiträge: 4

Themenstarter:

beantworten | zitieren | melden

Mit Serverlos meine ich Server in dem sinne, dass ein Programm extra läuft, das alle Nachrichten verwaltet /weiterleitet.
Genau genommen hast du recht und in meinem Fall ist jeder Client gleichzeitig ein server. Mittlerweile hab ich das Problem lösen können, dass Pakete verloren gegangen sind. Es lag an meinem Codeaufbau (siehe vorletzten Post von mir). Ich verstehe einfach nicht warum jeder sagt es geht nur mit TCP bzw ich soll lieber TCP nehmen. Ich weis es können Pakete verloren gehen aber das ist glaube ich bei einem einfachen chat nich sehr tragisch, denn bisher läuft alles problemlos. Habe jetzt auch eine AES verschlüsselung mit eingebaut, ohne Schlüsselaustausch o.ä.; man muss eben das Passwort wissen. Wer sich überzeugen will, soll mir eine PM schicken, ich poste gernen den Sourcecode.
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von C0dR am .

Moderationshinweis von gfoidl (27.09.2011 - 20:37)

Bitte beachte [Hinweis] Wie poste ich richtig? Punkt 2.3

private Nachricht | Beiträge des Benutzers
mogel
myCSharp.de - Member

Avatar #avatar-3347.jpg


Dabei seit:
Beiträge: 156

beantworten | zitieren | melden

Zitat von C0dR
Ich verstehe einfach nicht warum jeder sagt es geht nur mit TCP bzw ich soll lieber TCP nehmen
  1. weil UDP dafür nicht geeignet ist
  2. UDP kannst Du bei Audio-/Videoübertragung in Deinem Chat verwenden
  3. UDP kannst Du für Broadcast verwenden, damit sich die Clients im lokalem LAN finden
  4. weil es mich nerven würde wenn mein Chatpartner auf eine Nachricht von mir wartet und auf die Antwort von ihm - aber meine Nachricht an meinen Chatpartner ohne Information in einem schwarzen Loch verschwunden ist
  5. wenn ich doch eine Information vom Chat bekomme (das meine Nachricht verschunden ist), dann heißt das das Du TCP-Verhalten in UDP nach implementiert hast (was sinnloser Zeitaufwand ist)
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von mogel am .
private Nachricht | Beiträge des Benutzers
PPK
myCSharp.de - Member



Dabei seit:
Beiträge: 157

beantworten | zitieren | melden

Außerdem ist bei einem Chat der Datenverkehr auch nicht so groß.
Wenn man aber eine Verbindung haben möchte, die nicht über den Server läuft, sondern der Server nur als Vermittler tätig ist, dann geht TCP nicht.

PS: SendTo - heißt die Methode der Klasse Sockets um Daten an einen Client zu schicken (ohne Verbindung, bei UDPClient ist Send einfach überladen)
private Nachricht | Beiträge des Benutzers
mogel
myCSharp.de - Member

Avatar #avatar-3347.jpg


Dabei seit:
Beiträge: 156

beantworten | zitieren | melden

Zitat von PPK
Wenn man aber eine Verbindung haben möchte, die nicht über den Server läuft, sondern der Server nur als Vermittler tätig ist, dann geht TCP nicht.
?? hä ??
private Nachricht | Beiträge des Benutzers
Darth Maim
myCSharp.de - Member



Dabei seit:
Beiträge: 216

beantworten | zitieren | melden

Ich denke er meint Hole Punching :)

Darthmaim

Moderationshinweis von gfoidl (28.09.2011 - 17:44)

Siehe auch Der Lochtrick

private Nachricht | Beiträge des Benutzers