2

I've been experimenting the UDP sending and receiving in C# and have a strange issue. The code works fine in a console app, but the client.Receive method is blocked when I try to use the exact same code in a Service. The Service runs normally and doesn't abort, and I have logging writing to a text file, so I know it gets to the Receive. Anyone have any ideas? Code below...

public partial class Service1 : ServiceBase
{
    private bool serviceStarted = false;
    Thread listenerThread;

    public Service1()
    {
        InitializeComponent();      
    }

    protected override void OnStart(string[] args)
    {
        serviceStarted = false;
        WriteLog("UDPListener Service Starting");

        ThreadStart thread = new ThreadStart(StartListening);
        listenerThread = new Thread(thread);

        serviceStarted = true;
        listenerThread.Start();
    }

    protected override void OnStop()
    {
        WriteLog("UDPListener Service Stopping");

        serviceStarted = false;
        listenerThread.Join(new TimeSpan(0, 0, 5));
    }

    private void StartListening()
    {
        WriteLog("Worker thread spawned.");

        UdpClient client = new UdpClient(40000);

        while (serviceStarted)
        {
            WriteLog("Service is started.  Getting endpoint.");
            IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, 40000);
            WriteLog("Thread is listening...");

            byte[] content = client.Receive(ref remoteIPEndPoint);
            WriteLog("Receive unblocked.");

            if (content.Length > 0)
            {
                string message = Encoding.ASCII.GetString(content);
                WriteLog("UDPListener Message = " + message);
            }
        }
        Thread.CurrentThread.Abort();
    }

    private void WriteLog(string strMessage)
    {
        FileStream filestream = new FileStream(@"c:\temp\UDPClientLog.txt", 
                                       FileMode.OpenOrCreate, 
                                       FileAccess.Write);
        StreamWriter streamwriter = new StreamWriter(filestream);
        streamwriter.BaseStream.Seek(0, SeekOrigin.End);

        streamwriter.WriteLine(DateTime.Now.ToLongDateString() +
            " at " +
            DateTime.Now.ToLongTimeString() +
            ": " +
            strMessage +
            "\n");

        streamwriter.Flush();
        streamwriter.Close();
    }
}
Nate
  • 101
  • 1
  • 5

3 Answers3

8

Finally figured this out. Windows Firewall was blocking the incoming connection and apparently the service isn't allowed to interactively ask for permission to unblock it.

Nate
  • 101
  • 1
  • 5
0

That's because UdpClient.Receive is blocking (i.e. synchronous) operation, and thread would be blocked until you receive data:

The Receive method will block until a datagram arrives from a remote host. When data is available, the Receive method will read the first enqueued datagram and return the data portion as a byte array. This method populates the remoteEP parameter with the IPAddress and port number of the sender.

If you want nonblocking behaviour you can use asynchronous version: UdpClient.BeginReceive method.

Sergey Teplyakov
  • 11,477
  • 34
  • 49
  • Sorry, should clarify. I know Receive should be blocking, but it never receives the message from the sender. This only happens in the Service, the same code in a Console App receives the message correctly. – Nate Feb 19 '10 at 19:50
  • Hm.. It strange, because I use iwindows services and UDP sockets and all works fine. Are you sure that you receive data? Some tool like wireshark can prove it... – Sergey Teplyakov Feb 19 '10 at 19:57
  • I'm pretty sure it's not receiving data, or I would think the Receive method would return. The thread is spawning and the endpoint is established correctly (both logging entries show up). Everything looks fine - the service is started and no errors in the event viewer - but it just sits there waiting for a message that it never gets. It should work, since the console performs the exact same actions (creates a new thread, etc) and it gets the message just fine. I'm stumped. – Nate Feb 19 '10 at 20:02
  • One more advise: you can create separate class that do all stuff and test it in console app. Than you can use the same class (not similar logic) in windows service. It also should work. Maybe there are some security-related problems? – Sergey Teplyakov Feb 19 '10 at 20:05
  • Check what account the service is running under. Test it with your admin account. – Steven Sudit Feb 19 '10 at 21:13
  • Yep, I've been installing the service with InstallUtil using my admin account. One thing I forgot to mention, though I can't imagine why it would matter... the OS is Windows 7 64 bit. I'm registering the service using the 64 bit .NET framework version of InstallUtil. Thanks for the tip Sergey, I'll try making the code into a class and try that. – Nate Feb 19 '10 at 21:24
  • Really strange. Just put all the listener code into a class library and call it from both the console and service. Same result, the console app receives the message, the service doesn't. – Nate Feb 19 '10 at 22:14
  • I posted the answer above, it looks like the Service doesn't allow Windows to prompt to unblock the firewall. If I turn the firewall off, it works fine. I'm a little surprised there is no event logged or any other indication of a problem, but either way, it looks like a firewall problem. Thanks for your suggestions Sergey. By the way, the code is listed in the original post. I had to tweak it a little to put it in a class library, but nothing major. – Nate Feb 22 '10 at 16:31
  • I have the exact same problem. I have a piece of code which uses UdpClient to send data to a server and tries to receive some data back. I tried both blocking mode Receive call and the non-blocking asyncronous BeginReceive. The code works in console mode with no problem. When put as a service, the code does not receive the data back from the server when the Windows firewall is on. When Windows firewall is turned off, data immediately comes in. Any solutions without turning the firewall off? It is not practical and wise to recommend all users of my app to turn Windows firewall off. – timeon Sep 21 '12 at 17:20
0

Instead of turning off window firewall simple add your program to "Allowed Programs"

For example if your service running location is "C:\Program Files (x86)\MyWork\Service1.exe"

Go To firewall click on "Allow a program or feature through window firewall" from left top corner. Click on "Allow Another Program" Click on "Browse" select your program e.g. Service1.exe Click on "Add" it will appear under your "Allow programs and features list".

dawncode
  • 578
  • 1
  • 8
  • 22