Nov. 20, 2007, 11:03 p.m.
posted by vendetta
The UdpClient Class
The UdpClient class was created to help make UDP network programs simpler for network programmers. This section describes the UdpClient class and its methods and walks you through creating a simple UDP server and client program using the helper class.
The UdpClient Class Constructors
The UdpClient class has four formats of constructors:
UdpClient() This format creates a new UdpClient instance not bound to any specific address or port.
UdpClient(int port) This constructor binds the new UdpClient object to a specific UDP port number.
UdpClient(IPEndPoint iep) This constructor binds the new UdpClient object to a specific local IP address and port number.
UdpClient(string host, int port) This format binds the new UdpClient object to any local IP address and port and associates it with a specific remote IP address and port.
The UdpClient constructors work like their comparable TcpClient constructors. You can either let the system choose a UDP port for the application, or you can select a specific port in the constructor. If your UDP application must accept data on a specific port, you must define that port in the UdpClient constructor.
Once the UdpClient object is created, you can manipulate the underlying socket and move data using the various methods available.
The UdpClient Class Methods
The methods of the UdpClient class provide various functionality for controlling and moving data into and out of the UDP socket. Figure describes these methods.
|
Method |
Description |
|---|---|
|
Close() |
Closes the underlying socket |
|
Connect() |
Allows you to specify a remote IP endpoint to send and receive data with |
|
DropMulticastGroup() |
Removes the socket from a UDP multicast group |
|
Equals() |
Determines if two UdpClient objects are equal |
|
GetHashCode() |
Gets a hash code for the UdpClient object |
|
GetType() |
Gets the Type of the current object |
|
JoinMulticastGroup() |
Adds the socket to a UDP multicast group |
|
Receive() |
Receives data from the socket |
|
Send() |
Sends data to a remote host from the socket |
|
ToString() |
Creates a string representation of the UdpClient object |
| Note |
The JoinMulticastGroup() and DropMulticastGroup() methods allow you to program UDP applications to use IP multicasting. This feature is discussed in Chapter 10, "IP Multicasting." |
Using the UdpClient Class in Programs
There are a few subtle differences between the UdpClient class’s Receive() and Send() methods that make them different from the Socket methods ReceiveFrom() and SendTo().
The Receive() Method
The UdpClient class uses the Receive() method to accept UDP packets on the specified interface and port. There is only one Receive() method format:
byte[] Receive(ref IPEndPoint iep)
The Receive() method accepts UDP packets on the IP address and UDP port specified by the UdpClient constructor, either system-specified values, or values set in the constructor.
Let’s take a look at how the Receive() method format differs from the ReceiveFrom() method used with standard UDP Socket objects.
For starters, the data received from the socket is not placed in a byte array within the method call. It is returned by the method. You must specify an empty byte array for the received data.
The second difference between the UdpClient method Receive() and the Socket method ReceiveFrom()is the way the remote host information is returned. ReceiveFrom()places the remote host information in an EndPoint object, whereas Receive()uses an IPEndPoint object. This makes extracting the IP address and UDP port number of the remote host a little easier for the programmer.
The following code snippet demonstrates how to use the Receive() method in a UDP application:
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);
UdpClient newsock = new UdpClient(ipep);
byte[] data = new byte[1024];
IPEndPoint ipep2 = new IPEndPoint(IPAddress.Any, 0);
data = host.Receive(ref ipep2);
Console.WriteLine("The remote host is: {0}, port {1}",
ipep2.Address, ipep2.Port);
Console.WriteLine(Encoding.ASCII.GetString(data));
In this code snippet, a UDP packet is accepted on UDP port 9050 from any network interface on the machine and is displayed on the console.
| Note |
One nice feature of the Receive() method is what happens when more data is received than the buffer size specified can accommodate. Instead of throwing a SocketException, as the Socket object does, the UdpClient returns a data buffer large enough to handle the received data. The result: a handy feature that can save you lots of extra programming effort. |
The Send() Method
The Send() method has three formats that can send data to a remote host:
Send(byte[] data, int sz) This format sends the byte array data of size sz to the default remote host. To use this format, you must specify a default remote UDP host using either UdpClient constructor, or the Connect() method:
UdpClient host = new UdpClient("127.0.0.1", 9050);
Send(byte[] data, int sz, IPEndPoint iep) This format sends the byte array data of size sz to the remote host specified by iep.
Send(byte[] data, int sz, string host, int port) This format sends the byte array data of size sz to the host host at port port.
| Tip |
If you are writing a UDP application that does not need to listen for incoming packets on a specific UDP port, you can use the UdpClient constructor that specifies the remote host information and then use the Receive() and Send() methods to move data back and forth with the remote host. |
A Simple UdpClient Server Program
The UdpSrvrSample.cs program, shown in Listing 7.3, demonstrates using the UdpClient class methods in a server application environment.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class UdpSrvrSample
{
public static void Main()
{
byte[] data = new byte[1024];
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);
UdpClient newsock = new UdpClient(ipep);
Console.WriteLine("Waiting for a client...");
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
data = newsock.Receive(ref sender);
Console.WriteLine("Message received from {0}:", sender.ToString());
Console.WriteLine(Encoding.ASCII.GetString(data, 0, data.Length));
string welcome = "Welcome to my test server";
data = Encoding.ASCII.GetBytes(welcome);
newsock.Send(data, data.Length, sender);
while(true)
{
data = newsock.Receive(ref sender);
Console.WriteLine(Encoding.ASCII.GetString(data, 0, data.Length));
newsock.Send(data, data.Length, sender);
}
}
}
The UdpSrvrSample program creates a UdpClient object from an IPEndPoint object, specifying any IP address on the server and using UDP port 9050. The program immediately waits for an incoming UDP packet from any remote client, using the Receive() method:
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0); data = newsock.Receive(ref sender);
The sender variable stores the IP information of the client, which is then used for sending messages back to the client:
newsock.Send(data, data.Length, sender);
Because the UdpClient object does not know the IP information of the destination host, you must specify it for each Send() method call.
| Note |
As seen in the UdpSrvrSample program, the data-byte array does not need to be reset to its full length after every Receive() method. This is a handy feature of the UdpClient class. |
A Simple UdpClient Client Program
Here is the matching client program, UdpClientSample.cs (Listing 7.4), demonstrating how to use the UdpClient class methods in a UDP client application.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class UdpClientSample
{
public static void Main()
{
byte[] data = new byte[1024];
string input, stringData;
UdpClient server = new UdpClient("127.0.0.1", 9050);
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
string welcome = "Hello, are you there?";
data = Encoding.ASCII.GetBytes(welcome);
server.Send(data, data.Length);
data = server.Receive(ref sender);
Console.WriteLine("Message received from {0}:", sender.ToString());
stringData = Encoding.ASCII.GetString(data, 0, data.Length);
Console.WriteLine(stringData);
while(true)
{
input = Console.ReadLine();
if (input == "exit")
break;
server.Send(Encoding.ASCII.GetBytes(input), input.Length);
data = server.Receive(ref sender);
stringData = Encoding.ASCII.GetString(data, 0, data.Length);
Console.WriteLine(stringData);
}
Console.WriteLine("Stopping client");
server.Close();
}
}
Because the UdpClientSample program does not need to listen to a specific UDP port for incoming messages, you can use the all-in-one constructor format, specifying the IP address and UDP port number of the remote host:
UdpClient server = new UdpClient("127.0.0.1", 9050);
Of course, if you are connecting to a remote UDP server, remember to place either the IP address or hostname of the remote server in the constructor instead of the loopback address.
After the UdpClient object is created, the Send() method sends the greeting message out to the server:
server.Send(data, data.Length);
Notice that because the destination host address information was already specified in the UdpClient constructor, you do not need to specify it in the Send() method.
Testing the Sample Programs
After compiling the UdpSrvrSample and UdpClientSample programs, you can test them on the same machine or on separate machines on the network.
The output looks exactly like the output from the SimpleUdpClient program (Listing 6.2) shown in Chapter 6, "Connectionless Sockets." Each message sent using the Send() method call is sent as a single UDP packet to the remote machine and read using a single Receive() method call.
Because the UdpClient class employs UDP packets to transmit messages, it suffers from one of the same problems as the UDP Socket objects, as described in Chapter 6. Specifically, there is always the possibility that sent messages will not make it to the destination device, so you must compensate for that in your UdpClient programs. This is usually accomplished by using the retry techniques demonstrated in Chapter 6.
| Warning |
One problem with UDP Socket objects that is not found in UdpClient objects is lost data. If the data buffer supplied to the UdpClient method Receive() is too small for the incoming data, the buffer is returned to match the size of the data. No data is lost, and no SocketExceptions are thrown. |