|
-
15-11-2008, 19:03
|
-
kostasdiktia
-
-

-
Μέλος από τις 10-02-2006
-
Αθήνα
-
Δημοσιεύσεις 110
-
-
|
Γεια σας, έχω δημιουργήσει την παρακάτω εφαρμογή για 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
|
|
Απ: UDP connection problem
Αν βλέπω σωστά από τον κώδικα, όλη η ροή που περιγράφεις συμβαίνει μέσα στο click event ενός button.
Η επικοινωνία μέσω του πρωτοκόλλου udp είναι ασύγχρονη και χωρίς η μια μεριά να ξέρει ότι η άλλη έχει λάβει ή στείλει δεδομένα - κάθε μεριά χρησιμοποιεί δικό της κανάλι, που η άλλη πρέπει να έχει κάνει listen για να λάβει δεδομένα. Αυτό σημαίνει ότι για να μπορέσεις να κάνει receive, θα πρέπει να έχει σύνδεση από την μεριά του server, και μετά να προσπαθήσεις να κάνεις receive εσύ. Πιθανώς όταν βάζεις το messagebox, ο server προλαβαίνει να συνδεθεί, για αυτό και παίζει ο receive του port.
Το σενάριο που περιγράφεις ταιριάζει πιο πολύ σε σύγχρονη σύνδεση μέσω tcp πρωτοκόλλου. Με τη χρήση tcp επικοινωνίας στο σενάριο σου, ο ένας θα περιμένει τον άλλο να απαντήσει, και ότι το ίδιο κανάλι χρησιμοποιείται για την ανταλλαγή μηνυμάτων και από τους δύο, κάνει την υλοποίηση πιο εύκολη.
George J.
|
|
-
03-01-2009, 14:22
|
-
mixio
-
-

-
Μέλος από τις 31-12-2007
-
Θεσσαλονικη
-
Δημοσιεύσεις 129
-
-
|
Απ: 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
|
|
Απ: 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
|
|
Απ: UDP connection problem
Επίσης, δεν θα συνιστούσα το παραπάνω thread καθώς βασίζεται σε εσφαλμένες υποθέσεις ενός άρθρου του codeproject το οποίο αφορά παλαιότερες εκδόσεις του .NET Framework.
Παναγιώτης Καναβός, Freelancer Twitter: http://www.twitter.com/pkanavos
|
|
-
04-01-2009, 00:01
|
|
Απ: 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
|
-
mixio
-
-

-
Μέλος από τις 31-12-2007
-
Θεσσαλονικη
-
Δημοσιεύσεις 129
-
-
|
Απ: UDP connection problem
Παναγιώτης Καναβός:Επίσης, δεν θα συνιστούσα το παραπάνω thread καθώς βασίζεται σε εσφαλμένες υποθέσεις ενός άρθρου του codeproject το οποίο αφορά παλαιότερες εκδόσεις του .NET Framework.
Δεν πιστευω να εκατσε ενας τυπος να γραψει οτι να 'ναι στο codeproject. Αυτο που γραφει για το Receive Timeout ειναι σωστο-τατο και ειχα ακριβως το εν λογω προβλημα μεχρι που δοκιμασα sockets και δουλεψε. Καλα το απατη δεν το ειπα και κυριολεκτικα. Ετσι για να προσφερω μια δοση αμφιβολιας.  Σιγουρα εσυ τα ξερεις καλυτερα απο 'μενα αλλα πρεπει να ακουμε και τους νουμπαδες του .ΝΕΤ
Sleep-deprived psychotic hacker
|
|
-
04-01-2009, 02:59
|
|
Απ: 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
|
|
Απ: UDP connection problem
Υ.Γ. Και όπως φαίνεται στα σχόλια του άρθρου, το bug με τα πακέτα διορθώθηκε πριν από 6 χρόνια, με την έκδοση 1.1
Παναγιώτης Καναβός, Freelancer Twitter: http://www.twitter.com/pkanavos
|
|
|
|
|