Laden...

UDP Daten auf selben Port empfangen und senden

Erstellt von C0dR vor 12 Jahren Letzter Beitrag vor 12 Jahren 10.092 Views
C
C0dR Themenstarter:in
4 Beiträge seit 2011
vor 12 Jahren
UDP Daten auf selben Port empfangen und senden

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

U
1.688 Beiträge seit 2007
vor 12 Jahren

Hallo,

Manchmal hilft ein reconnect

was ist ein "reconnect"? UDP ist verbindungslos.

Versuch's mal ohne den .Connect-Aufruf.

M
8 Beiträge seit 2010
vor 12 Jahren

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ß

D
500 Beiträge seit 2007
vor 12 Jahren

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

P
157 Beiträge seit 2010
vor 12 Jahren

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?

C
C0dR Themenstarter:in
4 Beiträge seit 2011
vor 12 Jahren

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).

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 😉

U
1.688 Beiträge seit 2007
vor 12 Jahren
  
            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.

C
C0dR Themenstarter:in
4 Beiträge seit 2011
vor 12 Jahren

Mh da hast du recht. Hab es rausgenommen. Die Meldung wird sowieso nicht mehr benötigt. Aber danke für den Hinweis!

71 Beiträge seit 2008
vor 12 Jahren

Mein Provider vergisst gerne das ein oder andere UDP-Paket zuverlässig zuzustellen. Muss also nicht an der Software liegen..

D
500 Beiträge seit 2007
vor 12 Jahren

@progi123:

...mir hat sich gleich die Frage gestellt, ob Du Dir dessen im klaren bist, dass UDP kein zuverlaessiges Protokoll ist,....

156 Beiträge seit 2010
vor 12 Jahren

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

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")

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

C
C0dR Themenstarter:in
4 Beiträge seit 2011
vor 12 Jahren

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.

Hinweis von gfoidl vor 12 Jahren

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

156 Beiträge seit 2010
vor 12 Jahren

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 1.UDP kannst Du bei Audio-/Videoübertragung in Deinem Chat verwenden 1.UDP kannst Du für Broadcast verwenden, damit sich die Clients im lokalem LAN finden 1.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 1.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)

P
157 Beiträge seit 2010
vor 12 Jahren

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)

156 Beiträge seit 2010
vor 12 Jahren

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ä ??

D
216 Beiträge seit 2009
vor 12 Jahren

Ich denke er meint Hole Punching 😃

Darthmaim

Hinweis von gfoidl vor 12 Jahren

Siehe auch Der Lochtrick