Last week I started work on a logging tool for Half-Life based games. You can read more about it on this blog.
Anyway, as part of this tool I need to receive UDP datagram packets over a network connection. There is a .NET Framework class called UdpClient that does what you need. It’s the getting it to work that wasn’t too trivial (at least to me). Here’s a code fragment that receives UDP packets:
using System.Text;
using System.Net;
int port = Int32.Parse(ConfigurationSettings.AppSettings[listenPort]);
UdpClient client = new UdpClient(port);
int bufferSize = 1024;
buffer = new Byte[bufferSize];
IPEndPoint ep = new IPEndPoint(IPAddress.Any, port);
while (true)
{
buffer = client.Receive(ref ep);
string message = Encoding.ASCII.GetString(buffer, 0, buffer.Length);
Debug.WriteLine(ep.Address.ToString() + “: ” + message);
}
The tricky bits here are invisible. I tried to use the UdpClient::Connect method, which will make the whole thing not working.
The Receive call blocks until actual data is received. No need to worry about the infinite loop and processor load for that. I spawn this loop on a new background thread, so it will die automatically when the main thread of the application stops. You might want to use a more controllable mechanism to abort this thread gracefully.
In my quest to get things working I found a way to accomplish the same result with a raw socket using the Socket class. The approach is a bit different, as it uses a delegate to trigger the receival of data. Here’s how it goes:
private Byte[] buffer;
public void StartListening()
{
int port = Int32.Parse(ConfigurationSettings.AppSettings[listenPort]);
int bufferSize = 1024;
buffer = new Byte[bufferSize];
IPEndPoint ep = new IPEndPoint(IPAddress.Any, port);
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
sock.Bind(ep);
sock.BeginReceive(buffer, 0, 1024, SocketFlags.None, new AsyncCallback(this.OnReceive), sock);
}
{
Socket s1 = (Socket)ar.AsyncState;
int x = s1.EndReceive(ar);
string message = System.Text.Encoding.ASCII.GetString(buffer, 0, x);
Console.WriteLine(message);
s1.BeginReceive(buffer, 0, 1024, SocketFlags.None, new AsyncCallback(this.OnReceive), s1);
}
In StartListening an asynchronous receive is started. This call will not block until data is received, but continue straight away, ending the secondary thread on which the StartListening was started. Because of the asynchronous call, a thread from the .NET runtime’s thread pool will be used to do a callback on OnReceive once actual UDP data is delivered to the port through the AsyncCallback delegate. OnReceive in turn triggers another asynchronous receive, starting the whole thing over again. In effect, the background thread keeps itself alive (although different threads from the pool might be used).
Hope this helps you if you happen to stumble onto this.