Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια
σε

 

Αρχική σελίδα Ιστολόγια Συζητήσεις Εκθέσεις Φωτογραφιών Αρχειοθήκες

UDP connection problem

Îåêßíçóå áðü ôï ìÝëïò kostasdiktia. Τελευταία δημοσίευση από το μέλος Παναγιώτης Καναβός στις 04-01-2009, 03:00. Υπάρχουν 8 απαντήσεις.
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  15-11-2008, 19:03 46241

    UDP connection problem

    Γεια σας,

    έχω δημιουργήσει την παρακάτω εφαρμογή για udp επικοινωνία με εναν server.

    Imports System.Text
    Imports System.Net
    Imports System.Net.Sockets
    Public Class Form1
    Dim udpClient As New UdpClient()
    Dim temp As String
    Dim c1, c2, c3 As Integer
    Dim receiveBytes As [Byte]()
    Dim returnData As String
    Dim RemoteIpEndPoint As New IPEndPoint(IPAddress.Any, 0)
    Dim bufferRec(32) As Byte
    Dim j As Integer = 5

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    Try

    'udpClient.Client.ReceiveTimeout = 1000
    For c1 = 109 To 109
    For c2 = 112 To 112
    For c3 = 97 To 122

    Label1.Text = Convert.ToChar(c1) & Convert.ToChar(c2) & Convert.ToChar(c3)




    temp = "test " & Convert.ToChar(c1) & Convert.ToChar(c2) & Convert.ToChar(c3)
    Dim bufferTemp() As Byte = Encoding.ASCII.GetBytes(temp)
    Dim bufferSend(bufferTemp.Length + 5 - 1) As Byte

    bufferSend(0) = Byte.Parse("255")
    bufferSend(1) = Byte.Parse("255")
    bufferSend(2) = Byte.Parse("255")
    bufferSend(3) = Byte.Parse("255")
    bufferSend(4) = Byte.Parse("02")


    For k As Integer = 0 To bufferTemp.Length - 1
    bufferSend(j) = bufferTemp(k)
    j += 1
    Next k
    j = 5


    udpClient.Connect("123.456.789.123", 12345)
    udpClient.Send(bufferSend, bufferSend.Length)
    Me.Refresh()
    'If udpClient.Available > 0 Then
    receiveBytes = udpClient.Receive(RemoteIpEndPoint)
    ' End If

    returnData = Encoding.ASCII.GetString(receiveBytes)
    Label2.Text = returnData
    'MsgBox(returnData)

    Next
    Next
    Next

    Catch ex2 As TimeoutException

    Catch ex As Exception
    MsgBox(ex.Message.ToString)
    End Try

    End Sub
    End Class



    Το θέμα είναι ότι δεν μπλοκάρει στο receive έως ότου λάβει response από τον server. Οπότε πηγαίνει σε δεύτερο send και μπλοκάρει! Έπαιξα με το timeout time αλλά χωρίς αποτέλεσμα.
    Επίσης, όταν έβαλα το MsgBox(returnData) για να έχω κάτι σαν pause όλα βαίνουν καλώς. Τι μπορεί να φταίει μιας και διάβασα  στο msdn ότ για την receive ισχύει If no data is available for reading, the Receive method will block until data is available
    No knowledge can be certain, if it is not based
    upon mathematics or upon some other knowledge
    which is itself based upon the mathematical
    sciences.
  •  16-11-2008, 11:45 46248 σε απάντηση της 46241

    Απ: UDP connection problem

    Αν βλέπω σωστά από τον κώδικα, όλη η ροή που περιγράφεις συμβαίνει μέσα στο click event ενός button.

    Η επικοινωνία μέσω του πρωτοκόλλου udp είναι ασύγχρονη και χωρίς η μια μεριά να ξέρει ότι η άλλη έχει λάβει ή στείλει δεδομένα - κάθε μεριά χρησιμοποιεί δικό της κανάλι, που η άλλη πρέπει να έχει κάνει listen για να λάβει δεδομένα. Αυτό σημαίνει ότι για να μπορέσεις να κάνει receive, θα πρέπει να έχει σύνδεση από την μεριά του server, και μετά να προσπαθήσεις να κάνεις receive εσύ. Πιθανώς όταν βάζεις το messagebox, ο server προλαβαίνει να συνδεθεί, για αυτό και παίζει ο receive του port.

    Το σενάριο που περιγράφεις ταιριάζει πιο πολύ σε σύγχρονη σύνδεση μέσω tcp πρωτοκόλλου. Με τη χρήση tcp επικοινωνίας στο σενάριο σου, ο ένας θα περιμένει τον άλλο να απαντήσει, και ότι το ίδιο κανάλι χρησιμοποιείται για την ανταλλαγή μηνυμάτων και από τους δύο, κάνει την υλοποίηση πιο εύκολη.

     

    George J.


    George J. Capnias: Χειροπρακτικός Υπολογιστών, Ύψιστος Γκουράρχης της Κουμπουτερολογίας
    w: capnias.org, t: @gcapnias, l: gr.linkedin.com/in/gcapnias
    dotNETZone.gr News
  •  03-01-2009, 14:22 47383 σε απάντηση της 46241

    Απ: UDP connection problem

    Κωστα, η udpclient ειναι απατη.
    Δες το παρακατω thread για να λυσεις το προβλημα σου.
    Αντικαθιστα την udpclient με sockets σε συγχρονη επικοινωνια.
    http://www.dotnetzone.gr/cs/forums/thread/47167.aspx


    Sleep-deprived psychotic hacker

  •  03-01-2009, 22:07 47386 σε απάντηση της 47383

    Απ: UDP connection problem

    mixio:
    Κωστα, η udpclient ειναι απατη.
    Δες το παρακατω thread για να λυσεις το προβλημα σου.
    Αντικαθιστα την udpclient με sockets σε συγχρονη επικοινωνια.
    http://www.dotnetzone.gr/cs/forums/thread/47167.aspx

    Διαφωνώ, καθώς την έχω χρησιμοποιήσει και δουλεύει πολύ καλά. Μάλιστα, θα έλεγα το ίδιο καλά με τα sockets, γιατί πολύ απλά .... ΕΙΝΑΙ sockets! Ουσιαστικά είναι μία helper κλάση για UDP επικοινωνία η οποία διευκολύνει τα πράγματα σε σχέση με χύμα sockets. Το να την αποκαλεί κανείς απάτη, είναι υπερβολικό και μάλλον οφείλεται σε παρανόηση του τί κάνει.

    Εξάλλου, όπως παρατήρησε ήδη ο Καπνιάς, το πρόβλημα δεν είναι ότι αντί να χρησιμοποιηθούν χύμα sockets χρησιμοποιήθηκε η αντίστοιχη κλάση UdpClient, αλλά στο ότι ο κώδικας είναι απλά λάθος.

     


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  03-01-2009, 22:10 47387 σε απάντηση της 47386

    Απ: UDP connection problem

    Επίσης, δεν θα συνιστούσα το παραπάνω thread καθώς βασίζεται σε εσφαλμένες υποθέσεις ενός άρθρου του codeproject το οποίο αφορά παλαιότερες εκδόσεις του .NET Framework.


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  04-01-2009, 00:01 47389 σε απάντηση της 47387

    Απ: UDP connection problem

    Τέλος, για να μην υπάρχει αμφιβολία για το αν δουλεύει η UdpClient, σύγχρονα ή ασύγχρονα, έφτιαξα το παρακάτω προγραμματάκι το οποίο στέλνει και ακούει μηνυματάκια στο 9091. Για συντομία στέλνω και διαβάζω τα μηνύματα από τον ίδιο υπολογιστή και τη διεύθυνση 127.0.0.1. Για να το δοκιμάσει κανείς θα πρέπει να το τρέξει δύο φορές και στο ένα από τα δύο instances να πατήσει Start. Στο άλλο instance, γράφεις κάτι στο κουτί Message και πατάς send. Το μήνυμα θα εμφανιστεί στο άλλο instance.

    Στο παρελθόν (το... 2002) είχα φτιάξει το ίδιο προγραμματάκι να δουλεύει μέσω broadcast,multicast. Καθώς όμως δεν υπάρχει περίπτωση να ξαναβρώ τον κώδικα αυτό, είπα να δώσω εδώ την απλοϊκή του μορφή. Επίσης, για να δουλέψει το multicast θα πρέπει να έχουν ρυθμιστεί κατάλληλα οι routers του δικτύου, διαφορετικά τα μηνύματα προς τις broadcast διευθύνσεις απορρίπτονται.

    Υ.Γ. Προς Γ. Καπνιά: Δεν χρειάζεται να χρησιμοποιηθεί TCP για 2-way επικοινωνία με sockets. Αν πραγματικά δεν μας πειράζει να χαθεί και κανένα πακέτο, το UPD αρκεί.

    Ιδού ο κώδικας:

    using System;
    using System.Text;
    using System.Windows.Forms;
    using System.Net.Sockets;
    using System.Net;

    namespace UdpChat
    {
        public partial class ChatForm : Form
        {
            /// <summary>
            /// Η κλάση UdpState χρησιμοποιείται για να περάσουμε στην BeginReceive
            /// στοιχεία για το ποιός την καλεί
            /// </summary>
            public class UdpState
            {
                /// <summary>
                /// Ποιός είναι ο UdpClient ο οποίος δέχτηκε δεδομένα?
                /// Μπορεί η ίδια μέθοδος να χρησιμοποιείται από πολλούς UdpClients,
                /// οπότε πρέπει να ξεχωρίσουμε για ποιόν είναι τα δεδομένα
                /// </summary>
                public UdpClient Client{get;set;}
                /// <summary>
                /// Από ποιά διεύθυνση τα δέχθηκε?
                /// </summary>
                public IPEndPoint EndPoint { get; set; }
            }
           
            //Για συντομία, δουλεύουμε με το 127.0.0.1
            IPEndPoint point = new IPEndPoint(IPAddress.Loopback, 9091);
            //Ο listener θα δημιουργηθεί μόνο όταν πατηθεί το start
            UdpClient listener;

            public ChatForm()
            {
                InitializeComponent();
            }

            private void startButton_Click(object sender, EventArgs e)
            {
                //Δημιουργούμε το listener πάνω στο port 9091 αλλά δεν περιορίζουμε
                // τη διεύθυνση στην οποία ακούει
                if (listener==null)
                    listener = new UdpClient(9091);
                UdpState state=new UdpState{Client=listener,EndPoint=point};
                //Αρχίζουμε να ακούμε
                listener.BeginReceive(this.ReceiveCallback,state);
                this.Text = "Udp Chat - Listening";
            }

            private void stopButton_Click(object sender, EventArgs e)
            {
                //Κλείνουμε το listener. Αν έχουμε καλέσει την BeginReceive,
                // αυτό θα προκαλέσει μία κλήση στη ReceiveCallback
                if (listener != null)
                    listener.Close();
                listener = null;
                this.Text = "Udp Chat";
            }

            private void sendButton_Click(object sender, EventArgs e)
            {
                //Δημιουργούμε ένα νέο UdpClient για την αποστολή
                using (UdpClient client = new UdpClient())
                {
                    //Συνδεόμαστε στον προορισμό
                    client.Connect(IPAddress.Loopback, 9091);
                    //Μετατρέπουμε το μήνυμα σε bytes
                    byte[] message = Encoding.Unicode.GetBytes(messageBox.Text);
                    //Το στέλνουμε σύγχρονα
                    client.Send(message, message.Length);
                    //Κλείνουμε τον UdpClient
                    client.Close();
                    messageBox.Text = String.Empty;
                }
            }

            /// <summary>
            /// Καλείται όταν λαμβάνονται νέα δεδομένα
            /// </summary>
            /// <param name="ar"></param>
            private void ReceiveCallback(IAsyncResult ar)
            {
                //Ποιός μας έστειλε δεδομένα?
                UdpState s = (UdpState)ar.AsyncState;
                UdpClient listener = s.Client;
                IPEndPoint endpoint = s.EndPoint;

                //Αν η κλήση οφείλεται στο Close, ο UdpClient.Client θα είναι null.
                //Διαφορετικά έχουμε νέα δεδομένα και μπορούμε να τα παραλάβουμε
                if (listener.Client != null)
                {
                    //Διαβάζουμε τα bytes
                    byte[] message = listener.EndReceive(ar, ref endpoint);
                    //Τα μετατρέπουμε σε string
                    string receiveString = Encoding.Unicode.GetString(message);
                    //Προσθέτουμε το κείμενο στο discussionBox
                    SetText(receiveString, message.Length);
                    //Ξανακούμε για νέα δεδομένα
                    listener.BeginReceive(this.ReceiveCallback, s);
                }
            }

            delegate void SetTextCallback(string text, int length);

            /// <summary>
            /// Η ReceiveCallback εκτελείται σε διαφορετικό thread από τη φόρμα. Γι αυτό
            /// πρέπει η κλήση της SetText να μεταφερθεί από το thread της ReceiveCallback
            /// σε αυτό του thread. Αυτό γίνεται μέσω της Invoke
            /// </summary>
            /// <param name="text"></param>
            /// <param name="length"></param>
            private void SetText(string text, int length)
            {
                if (this.discussionBox.InvokeRequired)
                {
                    SetTextCallback d = new SetTextCallback(SetText);
                    this.Invoke(d, new object[] { text, length });
                }
                else
                {
                    discussionBox.Text += String.Format("\r\n{0} - {1} bytes", text, length);

                }
            }

        }
    }


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  04-01-2009, 02:11 47396 σε απάντηση της 47387

    Απ: UDP connection problem

    Παναγιώτης Καναβός:

    Επίσης, δεν θα συνιστούσα το παραπάνω thread καθώς βασίζεται σε εσφαλμένες υποθέσεις ενός άρθρου του codeproject το οποίο αφορά παλαιότερες εκδόσεις του .NET Framework.



    Δεν πιστευω να εκατσε ενας τυπος να γραψει οτι να 'ναι στο codeproject.
    Αυτο που γραφει για το Receive Timeout ειναι σωστο-τατο και ειχα ακριβως το εν λογω προβλημα μεχρι που δοκιμασα sockets
    και δουλεψε.

    Καλα το απατη δεν το ειπα και κυριολεκτικα. Ετσι για να προσφερω μια δοση αμφιβολιας. Big Smile
    Σιγουρα εσυ τα ξερεις καλυτερα απο 'μενα αλλα πρεπει να ακουμε και τους νουμπαδες του .ΝΕΤ Big Smile

    Sleep-deprived psychotic hacker

  •  04-01-2009, 02:59 47397 σε απάντηση της 47396

    Απ: UDP connection problem

    Αν πρόσεξες, χρησιμοποιώντας την BeginReceive δεν υπάρχει θέμα timeout και η εφαρμογή δεν μπλοκάρει. Αλλά ακόμα και αν ήθελα να καλέσω τη σύγχρονη Receive με timeout, θα έκανα ότι ακριβώς και με τη Socket. Θα έθετα το ReceiveTimeout property. Στην UdpClient έχω πρόσβαση στο Socket μέσω του UdpClient.Client property. Συνεπώς, μπορώ να θέσω το timeout που επιθυμών.

    Αν κάποιος χρησιμοποιεί μία κλάση ή μέθοδο για να πετύχει αυτά που κάνει μία άλλη μέθοδος, λογικό είναι να αντιμετωπίσει προβλήματα. Όσο για την ποιότητα των άρθρων στο codeproject, καλό είναι να τα αντιμετωπίζει κανείς με μεγάλο σκεπτικισμό καθώς δεν υφίστανται κάποιο ουσιαστικό έλεγχο. Δεν είναι η πρώτη φορά που συναντάω άρθρο το οποίο υποστηρίζει ότι έχει βρει ένα bug μόνο και μόνο για να διαπιστώσω ότι ο αρθρογράφος είχε παρανοήσει τον τρόπο λειτουργίας κάποιας κλάσης ή μηχανισμού.

    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  04-01-2009, 03:00 47399 σε απάντηση της 47397

    Απ: UDP connection problem

    Υ.Γ. Και όπως φαίνεται στα σχόλια του άρθρου, το bug με τα πακέτα διορθώθηκε πριν από 6 χρόνια, με την έκδοση 1.1

    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems