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

 

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

UDP receive

Îåêßíçóå áðü ôï ìÝëïò Jubei. Τελευταία δημοσίευση από το μέλος Jubei στις 12-01-2009, 00:17. Υπάρχουν 12 απαντήσεις.
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  26-12-2008, 17:00 47167

    UDP receive

    Χαίρετε,

    Είμαι νέος .net/c# προγραμματιστής και θέλω να φτιάξω μια εφαρμογή windows forms η οποία ακούει σε UDP για 3 τιμές τύπου float/double και όταν λάβει κάτι καλεί έναν event handler και ανταποκρίνεται στο γεγονός (πχ. παίρνει τις τιμές αυτές και τις παρουσιάζει σε ένα textbox). Προσπάθησα έτσι πολύ πρόχειρα να χρησιμοποιήσω την UdpClient αλλά δε μπορώ να καταλάβω πως δουλεύει.

    οποιαδήποτε βοήθεια θα ήταν ευπρόσεκτη.

    Ευχαριστώ εκ των προτέρων

    Jubei
  •  26-12-2008, 23:35 47175 σε απάντηση της 47167

    Απ: UDP receive

    Γεια σου jubei.

    Προσφατα χρησιμοποιουσα udpclient για τον ιδιο λογο με σενα.
    Ωστοσο αυτη η κλαση εχει καποια πολυ σημαντικα drawbacks που αναφερονται εδω.
    Θα σου δωσω τον κωδικα που χρησιμοποιουσα και 'γω.

    // Ακους τοπικα στην εν λογω πορτα.
    UdpClient client = new UdpClient(ListenPort);

    // Εδω περνας τα στοιχεια αυτου που 8α σε στελνει τις 3 τιμες.
    IPEndPoint remoteEP = new IPEndPoint(ServerIP, ServerPort);

    // Αν θες να του στειλεις κατι.. Αυτο που στελνεις θα ειναι ενας byte array.
    byte[] b = new byte[10];
    client.Send(b, b.length, remoteEP);

    // Ετσι θα λαμβανεις δεδομενα απο τον server. Στον received θα αποθηκευοντα αυτα που ελαβες.
    byte[] received = client.Receive(ref remoteEP);


    Αφου διαβασεις τα προβληματα αυτης της κλασης θα σου ελεγα καλυτερα να χρησιμοποιησεις sockets.
    Σου δινω και αυτον τον κωδικα που αντικαθιστα τον προηγουμενο.

    // Ακους τοπικα στην εν λογω πορτα. Του βαζεις και ενα receive timeout πχ. 10000ms
    IPEndPoint localEP = new IPEndPoint(IPAddress.Any, ListenPort);
    Socket Listener = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
    Listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 10000);
    Listener.Bind(localEP);

    // Εδω περνας τα στοιχεια αυτου που 8α σε στελνει τις 3 τιμες.
    EndPoint remoteEP = (EndPoint)(new IPEndPoint(ServerIP, ServerPort));

    // Στειλε ενα byte array
    byte[] b = new byte[10];
    int BytesSend = Listener.SendTo(b, remoteEP);

    // Οτι λαβεις περασε το στο buffer array
    byte[] buffer = new byte[64 * 1024];
    int BytesReceived = Listener.ReceiveFrom(buffer, ref remoteEP);

    Μολις λαβει κατι το αποθηκευει στο buffer.
    Οσο δεν λαμβανει κατι, το προγραμμα μπλοκαρει εκει. Aν σε 10000ms δε παρει κατι ριχνει SocketException.
    Δε χρειαζεσαι τον handler πιστευω.


    Sleep-deprived psychotic hacker

  •  27-12-2008, 12:20 47181 σε απάντηση της 47175

    Απ: UDP receive

    Φίλε Mixio

    Σε ευχαριστώ πολύ για τις χρήσιμες συμβουλές. Θα δοκιμάσω κι εγώ με sockets. Κάτι άλλο που ήθελα να ρωτήσω είναι, πως μπορώ να τεστάρω την εφαρμογή που ακούει για τα udp πακέτα πριν φτιάξω τον client. Υπάρχει κάποιος εύκολος/γρήγορος τρόπος για να τεστάρω;

    ευχαριστώ εκ των προτέρων,

    Jubei
  •  27-12-2008, 12:52 47183 σε απάντηση της 47181

    Απ: UDP receive

    Jubei:
    Φίλε Mixio

    Σε ευχαριστώ πολύ για τις χρήσιμες συμβουλές. Θα δοκιμάσω κι εγώ με sockets. Κάτι άλλο που ήθελα να ρωτήσω είναι, πως μπορώ να τεστάρω την εφαρμογή που ακούει για τα udp πακέτα πριν φτιάξω τον client. Υπάρχει κάποιος εύκολος/γρήγορος τρόπος για να τεστάρω;

    ευχαριστώ εκ των προτέρων,

    Jubei


    Δεν νομιζω να υπαρχει κατι πιο γρηγορο απο το να γραψεις αυτες τις λιγοστες σειρες κωδικα που σου εδωσα και να τρεξεις το προγραμματακι σου.
    Επισης αν η προηγουμενη απαντηση μου ειναι και η λυση στο προβλημα σου, υπαρχει ενα κουμπακι "Σημειωση ως απαντηση" σε καθε post το οποιο οταν το πατας  δινει στο thread την ενδειξη οτι εχει επιλυθει. Αυτο βοηθαει στους νεους που διαβαζουν κατι, να ειναι σιγουροι οτι αυτο που διαβαζουν εχει λειτουργησει πρακτικα. 

    Sleep-deprived psychotic hacker

  •  28-12-2008, 18:24 47238 σε απάντηση της 47183

    Απ: UDP receive

    ξέρει κανείς κάποιο καλό βιβλίο να διαβάσω να μάθω για sockets σε C# ή κάποιο καλό online tutorial διότι όσο κι αν προσπαθώ μέ διάφορα online tutorials που έχω βρεί, ΔΕ μπορώ να καταλάβω πως λειτουργεί το πράγμα και να φανταστείτε οτι σε java έχω φτιάξει sockets app.

    Βασικά δε μπορώ να βρώ ΠΩΣ λειτουργεί μια windows forms εφαρμογή. Δε μπορώ δηλαδή να καταλάβω με ποιά σειρά γίνονται initialize τα components και που πρέπει εγώ να βάλω τον κώδικα μου για να παίξει σωστά αφού έχουν φορτωθεί τα controls κτλ. Υπάρχει κάποιο έγγραφο online που να εξηγεί πως λειτουργεί μια .net εφαρμογή απόγονος της : Window ή : Form ?

    Jubei
  •  28-12-2008, 23:12 47245 σε απάντηση της 47238

    Απ: UDP receive

    Μπορείς να κάνεις κάτι πολύ απλό: Να φτιάξεις event handlers για όλα τα events που σε ενδιαφέρουν και να βάλεις μέσα στο κάθε ένα από αυτά ένα Debug.Writeline που να εμφανίζει το όνομα του event. Μόλις τρέξει η εφαρμογή θα δεις στο Debug window όλα τα ονόματα των events με τη σειρά που έγιναν trigger.

    Πάντως, τυπικά, υπάρχουν δύο σημεία που μπορείς να βάλεις τον κώδικα σου

    • Στον constructor της φόρμας, μετά την κλήση στο InitializeComponent
    • Στο FormLoad event

    Vir prudens non contra ventum mingit
  •  04-01-2009, 00:11 47390 σε απάντηση της 47238

    Απ: UDP receive

    H UdpClient δεν έχει κάποιο πρόβλημα, αντίθετα απ' όσα λέει το thread του 2002 το οποίο παραθέτει ο mixio. Το UdpClient είναι ένα helper class το οποίο διευκολύνει τη χρήση UDP sockets. Χρησιμοποιώντας το χρησιμοποιείς ήδη sockets. Δεν υπάρχει λόγος να αποφύγεις την UdpClient απλά και μόνο επειδή θέλεις να χρησιμοποιήσεις sockets.

    Όσον αφορά το πότε πρέπει να καλέσεις τί και που, έφτιαξα στα πολύ γρήγορα ένα πρόγραμμα το οποίο στέλνει UDP πακέτα στην 9091 και τα λαμβάνει ασύγχρονα. Για να το δοκιμάσεις θα πρέπει να το τρέξεις δύο φορές και στο ένα instance να πατήσεις start, στο άλλο να γράψεις ένα μήνυμα και να πατήσεις send. Χρησιμοποιούνται δύο UdpClients. Ο ένας είναι πεδίο της φόρμας αλλά δημιουργείται όταν πατάς το start. Μετά, με την κλήση της BeginReceive περιμένει ένα πακέτο. Όταν το λάβει το εμφανίζει και αρχίζει να ξανακούει. Ο άλλος δημιουργείται μόνο για να σταλεί ένα μήνυμα και μετά καταστρέφεται.

    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
  •  07-01-2009, 23:48 47489 σε απάντηση της 47167

    Απ: UDP receive

    Παναγιώτη ευχαριστώ για τη λεπτομερέστατη εξήγηση και τα σχόλια. Παρ'όλα αυτά επειδή είμαι newbie .net προγραμματιστής μου σκάει το πρόγραμμα όταν στέλνω δεδομένα με έναν test udp client. Συγκεκριμένα σκάει με αυτό το μήνυμα. Τι εννοεί οτι το αντικείμενο αυτό ανοίκει σε διαφορετικό thread? Ο κώδικας μου είναι σε ένα :Window μέσα και ο listener ξεκινάει σε ένα κουμπι. console έχω ονομάσει ένα textbox control που χρησιμοποιώ για να παρουσιάζω διάφορα μηνύματα.



    o κώδικας μου βρίσκεται εδω:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Net.Sockets;
    using System.Net;
    using System.Windows.Media.Media3D;

    using WpfCubeControl;
    using System.Drawing;

    namespace Wpf3DApp
    {
    /// <summary>
    /// Interaction logic for CubeWin.xaml
    /// </summary>
    public partial class CubeWin : Window
    {
    public class UdpState
    {
    public UdpClient Client { get; set; }
    public IPEndPoint EndPoint { get; set; }
    }

    IPEndPoint point = new IPEndPoint(IPAddress.Loopback, 9091);
    UdpClient listener;

    public CubeWin()
    {

    InitializeComponent();

    cubeControl1.CubeColor = System.Windows.Media.Color.FromRgb(255, 70, 0);
    cubeControl1.Render();
    }

    private void ReceiveCallback(IAsyncResult ar)
    {
    UdpState s = (UdpState)ar.AsyncState;
    UdpClient listener = s.Client;
    IPEndPoint endpoint = s.EndPoint;

    if (listener.Client != null)
    {

    byte[] message = listener.EndReceive(ar, ref endpoint);
    string receiveString = Encoding.Unicode.GetString(message);
    SetText(receiveString, message.Length);
    listener.BeginReceive(this.ReceiveCallback, s);
    }
    }

    delegate void SetTextCallback(string text, int length);

    private void startbutton_Click(object sender, RoutedEventArgs e)
    {
    if (listener == null)
    listener = new UdpClient(9091);
    UdpState state = new UdpState { Client = listener, EndPoint = point };
    listener.BeginReceive(this.ReceiveCallback, state);
    console.Text += "Listening for connections on port 9091";
    }

    private void SetText(string text, int length)
    {
    console.Text += String.Format("\r\n{0} - {1} bytes", text, length);

    }


    }
    }

    Jubei
    Δημοσίευση στην κατηγορία: , ,
  •  11-01-2009, 12:01 47564 σε απάντηση της 47489

    Απ: UDP receive

    απ'ότι διαβάζω επειδή το να ενημερώσω το textbox μου είναι δουλειά άλου thread πρέπει να χρησιμοποιήσω τον Dispatcher για να δουλέψει. Το ερευνώ τώρα. Ευχαριστώ για την βοήθεια anyway.

    Jubei
  •  11-01-2009, 13:02 47565 σε απάντηση της 47564

    Απ: UDP receive

    Τσκ, τσκ, τσκ, δεν διαβάζεις τον κώδικα που σου έγραψα! Αυτό κάνει ήδη η SetTextCallback στον κώδικα που σου έδωσα. Ελέγχει αν βρίσκεται σε διαφορετικό thread με την InvokeRequired η οποία παρέχεται απ' όλα τα controls και αν χρειαστεί καλεί την Invoke με παράμετρο τον ευατό της. H Invoke θα εκτελέσει ξανά την SetTextCallback, στο σωστό thread αυτή τη φορά.


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

    Απ: UDP receive

    Διάβασα πολύ καλά τον κώδικα σου αλλά είναι γραμένος για windows forms και όχι για WPF με αποτέλεσμα η μέθοδος σου που καλεί το "this.Invoke(d, new object[])" να μην μου κάνει compile.

    Προσπάθησα να την μετατρέψω σε WPF χρησιμοποιώντας την αντίστοιχη της Invoke με τον dispatcher αλλά δεν τα κατάφερα.

    Το έχω φτιάξει να παίζει synchronous (δηλαδή να κλειδώνει το thread tou UI περιμένοντας για UDP πακέτο) και τώρα διαβάζω και προσπαθώ να καταλάβω καλύτερα πως δουλέυει ο dispatcher και τα delegate classes.
  •  11-01-2009, 19:52 47572 σε απάντηση της 47566

    Απ: UDP receive

    Μάλλον ξέχασες να πεις ότι δουλεύεις με WPF


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

    Απ: UDP receive

    lol, πράγματι και όχι μόνο αυτό, τέρμα πάνω στο πρώτο post λέω οτι "θέλω να φτιάξω μια εφαρμογή windows forms". lol. Ζητώ συγνώμη για την παρεξήγηση. Παρεπιπτόντως ο κώδικας σου με βοήθησε πάρα πολύ, ευχαριστώ.

    Jubei
Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems