|
C++ UDP Client and Server Program Example
Create a new CLR console application project and you might want to use UDPClientServerCP as the name.
|
Add the following code.
// UDPClientServerCP.cpp : main project file. #include "stdafx.h"
using namespace System; using namespace System::Net; using namespace System::Net::Sockets; using namespace System::Collections;
static public void usage() { Console::WriteLine("Usage: UdpClientSampleCS [-m mcast] [-l local-ip] [-n count]"); Console::WriteLine(" [-p port] [-r] [-s destination] [-x size]\n"); Console::WriteLine("Available options:"); Console::WriteLine(" -m mcast Multicast group to join. May be specified multiple"); Console::WriteLine(" times. For IPv6 include interface to join group on"); Console::WriteLine(" as the scope id (e.g. ff12::1%4)"); Console::WriteLine(" -l local-ip Local IP address to bind to"); Console::WriteLine(" -n count Number of times to send a message"); Console::WriteLine(" -p port Port number: local port for receiver, remote port for sender"); Console::WriteLine(" -r Receive UDP data"); Console::WriteLine(" -s destination Send UDP data to given destination"); Console::WriteLine(" -x size Size of send and receive buffers"); Console::WriteLine(); }
int main(array<System::String ^> ^args) { ArrayList^ multicastGroups = gcnew ArrayList(); IPAddress^ localAddress = IPAddress::Any; IPAddress^ destAddress = nullptr; unsigned short portNumber = 5150; bool udpSender = false; int bufferSize = 256, sendCount = 5, i;
// Parse the command line if(args->Length != 0) { for (i = 0; i < args->Length; i++) { try { if ((args[i][0] == '-') || (args[i][0] == '/')) { switch (Char::ToLower(args[i][1])) { case 'm': // Multicast groups to join multicastGroups->Add(IPAddress::Parse(args[++i])); break; case 'l': // Local interface to bind to localAddress = IPAddress::Parse(args[++i]); break; case 'n': // Number of times to send the response sendCount = Convert::ToInt32(args[++i]); break; case 'p': // Port number (local for receiver, remote for sender) portNumber = Convert::ToUInt16(args[++i]); break; case 'r': // Indicates UDP receiver udpSender = false; break; case 's': // Indicates UDP sender as well as the destination address udpSender = true; destAddress = IPAddress::Parse(args[++i]); break; case 'x': // Size of the send and receive buffers bufferSize = Convert::ToInt32(args[++i]); break; default: usage(); return 0; } } } catch(Exception^ err) { Console::WriteLine("Error lor!!!: {0}", err->Message); usage(); return 0; } } } else { usage(); return 0; }
UdpClient^ udpSocket = nullptr; array<Byte>^ sendBuffer = gcnew array<Byte>(bufferSize); array<Byte>^ receiveBuffer = gcnew array<Byte>(bufferSize); int rc;
try { // Create an unconnected socket since if invoked as a receiver we don't necessarily // want to associate the socket with a single endpoint. Also, for a sender socket // specify local port of zero (to get a random local port) since we aren't receiving anything. Console::WriteLine("Creating connectionless socket..."); if (udpSender == false) udpSocket = gcnew UdpClient(gcnew IPEndPoint(localAddress, portNumber)); else udpSocket = gcnew UdpClient(gcnew IPEndPoint(localAddress, 0));
// Join any multicast groups specified Console::WriteLine("Joining any multicast groups specified..."); for (i = 0; i < multicastGroups->Count; i++) { if (localAddress->AddressFamily == AddressFamily::InterNetwork) { // For IPv4 multicasting only the group is specified and not the // local interface to join it on. This is bad as on a multihomed // machine, the application won't really know which interface // it is joined on (and there is no way to change it via the UdpClient). udpSocket->JoinMulticastGroup((IPAddress^)multicastGroups[i]); } else if (localAddress->AddressFamily == AddressFamily::InterNetworkV6) { // For some reason, the IPv6 multicast join allows the local interface index // to be specified such that the application can join multiple groups on // any interface which is great (but lacking in IPv4 multicasting with the // UdpClient). IPv6 multicast groups should be specified with the scope id // when passed on the command line (e.g. fe80::1%4). udpSocket->JoinMulticastGroup((int)((IPAddress^)multicastGroups[i])->ScopeId, (IPAddress^)multicastGroups[i]); } }
// If you want to send data with the UdpClient it must be connected -- either by // specifying the destination in the UdpClient constructor or by calling the // Connect method. You can call the Connect method multiple times to associate // a different endpoint with the socket. if (udpSender == true) { udpSocket->Connect(destAddress, portNumber); Console::WriteLine("Connect() is OK..."); }
if (udpSender == true) { // Send the requested number of packets to the destination Console::WriteLine("Sending the requested number of packets to the destination, Send()..."); for (i = 0; i < sendCount; i++) { rc = udpSocket->Send(sendBuffer, sendBuffer->Length); Console::WriteLine("Sent {0} bytes to {1}", rc, destAddress->ToString()); } // Send a few zero length datagrams to indicate to the receive to exit. Put a short // sleep between them since UDP is unreliable and zero byte datagrams are really // fast (and the local stack can actually drop datagrams before they even make it // onto the wire). Console::WriteLine("Having some sleep, Sleep(250)..."); for (i = 0; i < 3; i++) { rc = udpSocket->Send(sendBuffer, 0); Threading::Thread::Sleep(250); } } else { IPEndPoint^ senderEndPoint = gcnew IPEndPoint(localAddress, 0); // Receive datagrams in a loop until a zero byte datagram is received. // Note the difference with the UdpClient in that the source address // is simply an IPEndPoint that doesn't have to be cast to and EndPoint // object as is the case with the Socket class. Console::WriteLine("Receiving datagrams in a loop until a zero byte datagram is received..."); while (true) { receiveBuffer = udpSocket->Receive(senderEndPoint); Console::WriteLine("Read {0} bytes from {1}", receiveBuffer->Length, senderEndPoint->ToString()); if (receiveBuffer->Length == 0) break; } } } catch (SocketException^ err) { Console::WriteLine("Socket error occurred: {0}", err->Message); Console::WriteLine("Stack: {0}", err->StackTrace); } finally { if (udpSocket != nullptr) { // Clean things up by dropping any multicast groups we joined Console::WriteLine("Cleaning things up by dropping any multicast groups we joined..."); for (i = 0; i < multicastGroups->Count; i++) { if (localAddress->AddressFamily == AddressFamily::InterNetwork) { udpSocket->DropMulticastGroup((IPAddress^)multicastGroups[i]); } else if (localAddress->AddressFamily == AddressFamily::InterNetworkV6) { // IPv6 multicast groups should be specified with the scope id when passed // on the command line udpSocket->DropMulticastGroup((IPAddress^)multicastGroups[i], (int)((IPAddress^)multicastGroups[i])->ScopeId); } } // Free up the underlying network resources Console::WriteLine("Closing the socket..."); udpSocket->Close(); } } return 0; } |
Next, build the project and make sure there is no error. Then, run the project. Any error will be thrown by the exception handlers. The following is the sample output.
The following is the output sample when we run it as sender from the command prompt.
The following is the output sample when we run it both as a receiver and as a sender. Firstly, we run the program as a receiver from the C:\.
Then, we run the same program from other path as a sender.
The following screenshot shows the UDP as a receiver when the communication was completed.
Create a new console application project and you might want to use UdpClientSampleCS as the name.
Next, rename the class to UdpClientSample by renaming the source file.
Add/edit the following using directives at the top of the file.
using System; using System.Net; using System.Net.Sockets; using System.Collections; |
Add the following usage() method in side the class.
static public void usage() { Console.WriteLine("Usage: UdpClientSampleCS [-m mcast] [-l local-ip] [-n count]"); Console.WriteLine(" [-p port] [-r] [-s destination] [-x size]"); Console.WriteLine(); Console.WriteLine("Available options:"); Console.WriteLine(" -m mcast Multicast group to join. May be specified multiple"); Console.WriteLine(" times. For IPv6 include interface to join group on"); Console.WriteLine(" as the scope id (e.g. ff12::1%4)"); Console.WriteLine(" -l local-ip Local IP address to bind to"); Console.WriteLine(" -n count Number of times to send a message"); Console.WriteLine(" -p port Port number: local port for receiver, remote port for sender"); Console.WriteLine(" -r Receive UDP data"); Console.WriteLine(" -s destination Send UDP data to given destination"); Console.WriteLine(" -x size Size of send and receive buffers"); Console.WriteLine(); } |
Add the Main() code.
static void Main(string[ ] args) { ArrayList multicastGroups = new ArrayList(); IPAddress localAddress = IPAddress.Any, destAddress = null; ushort portNumber = 5150; bool udpSender = false; int bufferSize = 256, sendCount = 5, i;
usage();
// Parse the command line for (i = 0; i < args.Length; i++) { try { if ((args[i][0] == '-') || (args[i][0] == '/')) { switch (Char.ToLower(args[i][1])) { case 'm': // Multicast groups to join multicastGroups.Add(IPAddress.Parse(args[++i])); break; case 'l': // Local interface to bind to localAddress = IPAddress.Parse(args[++i]); break; case 'n': // Number of times to send the response sendCount = System.Convert.ToInt32(args[++i]); break; case 'p': // Port number (local for receiver, remote for sender) portNumber = System.Convert.ToUInt16(args[++i]); break; case 'r': // Indicates UDP receiver udpSender = false; break; case 's': // Indicates UDP sender as well as the destination address udpSender = true; destAddress = IPAddress.Parse(args[++i]); break; case 'x': // Size of the send and receive buffers bufferSize = System.Convert.ToInt32(args[++i]); break; default: usage(); return; } } } catch { usage(); return; } } UdpClient udpSocket = null; byte[ ] sendBuffer = new byte[bufferSize], receiveBuffer = new byte[bufferSize]; int rc;
try { // Create an unconnected socket since if invoked as a receiver we don't necessarily // want to associate the socket with a single endpoint. Also, for a sender socket // specify local port of zero (to get a random local port) since we aren't receiving // anything. Console.WriteLine("Creating connectionless socket..."); if (udpSender == false) udpSocket = new UdpClient(new IPEndPoint(localAddress, portNumber)); else udpSocket = new UdpClient(new IPEndPoint(localAddress, 0));
// Join any multicast groups specified Console.WriteLine("Joining any multicast groups specified..."); for (i = 0; i < multicastGroups.Count; i++) { if (localAddress.AddressFamily == AddressFamily.InterNetwork) { // For IPv4 multicasting only the group is specified and not the // local interface to join it on. This is bad as on a multihomed // machine, the application won't really know which interface // it is joined on (and there is no way to change it via the UdpClient). udpSocket.JoinMulticastGroup((IPAddress)multicastGroups[i]); } else if (localAddress.AddressFamily == AddressFamily.InterNetworkV6) { // For some reason, the IPv6 multicast join allows the local interface index // to be specified such that the application can join multiple groups on // any interface which is great (but lacking in IPv4 multicasting with the // UdpClient). IPv6 multicast groups should be specified with the scope id // when passed on the command line (e.g. fe80::1%4). udpSocket.JoinMulticastGroup((int)((IPAddress)multicastGroups[i]).ScopeId, (IPAddress)multicastGroups[i]); } }
// If you want to send data with the UdpClient it must be connected -- either by // specifying the destination in the UdpClient constructor or by calling the // Connect method. You can call the Connect method multiple times to associate // a different endpoint with the socket. if (udpSender == true) { udpSocket.Connect(destAddress, portNumber); Console.WriteLine("Connect() is OK..."); }
if (udpSender == true) { // Send the requested number of packets to the destination Console.WriteLine("Sending the requested number of packets to the destination, Send()..."); for (i = 0; i < sendCount; i++) { rc = udpSocket.Send(sendBuffer, sendBuffer.Length); Console.WriteLine("Sent {0} bytes to {1}", rc, destAddress.ToString()); } // Send a few zero length datagrams to indicate to the receive to exit. Put a short // sleep between them since UDP is unreliable and zero byte datagrams are really // fast (and the local stack can actually drop datagrams before they even make it // onto the wire). Console.WriteLine("HAving some sleep, Sleep(250)..."); for (i = 0; i < 3; i++) { rc = udpSocket.Send(sendBuffer, 0); System.Threading.Thread.Sleep(250); } } else { IPEndPoint senderEndPoint = new IPEndPoint(localAddress, 0); // Receive datagrams in a loop until a zero byte datagram is received. // Note the difference with the UdpClient in that the source address // is simply an IPEndPoint that doesn't have to be cast to and EndPoint // object as is the case with the Socket class. Console.WriteLine("Receiving datagrams in a loop until a zero byte datagram is received..."); while (true) { receiveBuffer = udpSocket.Receive(ref senderEndPoint); Console.WriteLine("Read {0} bytes from {1}", receiveBuffer.Length, senderEndPoint.ToString());
if (receiveBuffer.Length == 0) break; } } } catch (SocketException err) { Console.WriteLine("Socket error occurred: {0}", err.Message); Console.WriteLine("Stack: {0}", err.StackTrace); } finally { if (udpSocket != null) { // Clean things up by dropping any multicast groups we joined Console.WriteLine("Cleaning things up by dropping any multicast groups we joined..."); for (i = 0; i < multicastGroups.Count; i++) { if (localAddress.AddressFamily == AddressFamily.InterNetwork) { udpSocket.DropMulticastGroup((IPAddress)multicastGroups[i]); } else if (localAddress.AddressFamily == AddressFamily.InterNetworkV6) { // IPv6 multicast groups should be specified with the scope id when passed // on the command line udpSocket.DropMulticastGroup( (IPAddress)multicastGroups[i], (int)((IPAddress)multicastGroups[i]).ScopeId ); } } // Free up the underlying network resources Console.WriteLine("Closing the socket..."); udpSocket.Close(); } } } |
Next, build the project and make sure there is no error.
![]() |
|
Then, run the project. Any error will be thrown by the exception handlers.
The following is the sample output.
The following are the output samples when we run it as sender at the command prompt.
The following is the output sample when we run it as receiver at the command prompt.
Running both the receiver and the sender. Firstly we run the program as a receiver.
Then, we run the same program from another path as a sender.
The following screenshot shows the UDP as a receiver when the communication was completed.