In this post, I'll show you how can you listen for
UDP packets in a Windows service.
OnStartWhen the service starts, I set the started flag to true, initialize the
ManualResetEvent, initialize an
UdpClient and a WorkingThread. The ManualResetEvent will help us on a later stage to make our service stop elegantly.
1: protected override void OnStart(string[] args)
2: { 3: Start();
4: }
5:
6: public void Start()
7: { 8: m_started = true;
9:
10: m_stop = new ManualResetEvent(false);
11:
12: InitializeUdpListener();
13: InitializeWorkingThread();
14: }
InitializingFirst we need to initialize an
IPEndpoint. When the IPEndpoint is initialized we can initialize the
UdpClient using that
IPEndpoint.
1: private void InitializeUdpClient()
2: { 3: m_endPoint = new IPEndPoint(IPAddress.Any, PORT_NUMBER);
4: m_client = new UdpClient(m_endPoint);
5: }
After initializing our
UdpClient, we can initialize and start the WorkingThread.
1: private void InitializeWorkingThread()
2: { 3: m_workingThread = new Thread(WorkerFunction);
4: m_workingThread.Name = "WorkingThread";
5: m_workingThread.Start();
6: }
WorkerFunctionThe WorkerFunction does all the work.
While the service is started, we start
receiving packets. We pass in an
AsyncCallback Delegate which is called when the asynchronous operation completes. In this delegate we make sure that the result we receive is complete. If the result is complete we
end receiving and get the content of the UDP packet.
Finally we use the
WaitHandle to wait for either the asynchronous operation to complete or the workerthread to grant a termination request through the stop
ManualResetEvent.
1: private void WorkerFunction()
2: { 3: while (m_started)
4: { 5: //BeginReceive starts an asynchronous operation, in reality to allow us to achieve
6: //semi-synchronous invocation, where we wait for either the asynchronous operation
7: //to complete or the worker thread to grant a termination request through stop
8: var res = m_client.BeginReceive(iar =>
9: { 10: if (iar.IsCompleted)
11: { 12: byte[] receivedBytes = m_client.EndReceive(iar, ref m_endPoint);
13: string receivedPacket = Encoding.ASCII.GetString(receivedBytes);
14: }
15: }, null);
16:
17: if (WaitHandle.WaitAny(new[] { m_stop, res.AsyncWaitHandle }) == 0) 18: { 19: break;
20: }
21: }
22: }
OnStopIn the OnStop event we need to set the
ManualResetEvent, so our WorkerFunction can exit gracefully.
1: protected override void OnStop()
2: { 3: m_stop.Set();
4: m_started = false;
5: }
I'm pretty sure this is a robust solution. A service based on this example deployed to production has been handling 1000 packets an hour on average for the last three weeks without problems.
Thanks to
Bart De Smet for helping me out with the threading stuff!
You can
download the source here.