TCP Listener in the status bar application, can not work for multiple users on the same machine

advertisements

I'll open with this: I know you can only have one TcpListener listening to any given port, I'm trying to find a way to work around this limitation.

I am attempting to build an application that supports another application on the same machine. The other application, which I have no control over, sends out a signal on a TCP Port when it opens or closes a study.

In order to accept this TCP signal, I built a Windows Tray Application that listens to that port, accepts the signal, and then processes the data that was transmitted to it. The code block that manages this Listener looks like this...

    private TcpListener _tcpListener;
    private Thread _listenerThread;

    #region TCP Connection

    public void StartListener()
    {
        if (_listenerThread != null)
            StopListener();

        _listenerThread = new Thread(RunListener);
        _listenerThread.Start();
    }

    private void RunListener()
    {
        _tcpListener = new TcpListener(IPAddress.Any, this.TcpListenerPort);
        _tcpListener.Start();
        while (true)
        {
            Console.WriteLine(string.Format("Listening for connections on port {0}", this.TcpListenerPort));

            try
            {
                TcpClient client = _tcpListener.AcceptTcpClient();

                ThreadPool.QueueUserWorkItem(ProcessClient, client);
            }
            catch (SocketException ex)
            {
                // This occurs when we close the parent thread that runs the TcpListener because
                // the TcpListener call to AcceptTcpClient is a blocking call.
            }
            catch (Exception ex)
            {
                Console.WriteLine(string.Format("Exception trying to AcceptTcpClient: {0}", ex.Message));
            }
        }
    }

    private void StopListener()
    {
        if (_tcpListener != null)
            _tcpListener.Stop();

        if (_listenerThread != null)
            _listenerThread.Abort();
    }

As you can see, this is pretty simple and straight-forward. I spool up a thread to hold the Listener, then wait for a signal to come through, then do something with the data that it sent me. And all of this is working just fine.

The problem comes from this: This tray application is set up to run when a user logs in to the machine. However, due to the 'One listener per port' rule of the TCP Listener, if more than one user logs on to the machine at once (either via VPN or through 'switching' rather than logging off), then a second instance of this application attempts to start. And promptly crashes because it attempts to listen to a port that is already being listened to.

I cannot change the way information is sent to me by the other program, and I cannot force Windows Users to properly log off before switching to a new user. I cannot relocate any of these pieces to a different machine, either. However, this tray-app needs to be available to each and every user.

I have quite run out of ideas for how to resolve this, and any input would be extremely helpful.

Specifically, I'm trying to locate a method to hijack an existing thread hosting a TcpListener, co-opting it for use by more than one Windows Account at a time on the same machine. Granted, I will certainly not turn down a better idea than the one I have, either.

EDIT: I have considered running it as a Service, but one of the outcomes of data being received by the Listener is that the Tray Application launches a web browser, and it has a user interface for configuring its settings.


I cannot make comments yet, due to my rep, so this answer isn't really an answer, but you have a problem with your design. So you have 4 users logged into this machine, thus 4 instances of the UI for user settings and such. When any/all of the 4 UI apps receive the communication from the sending app, which if any are supposed to respond to it?

Is it all 4? If it is all 4, then the suggestion to use a Service to "Listen" is correct, 1 service listens to 1 port. When it gets something, it can then communicate with the UI applications. Have them Talk to the Service on starting and setup their own listening Port, so that the Service can keep track of who is still listening and command that app to open the web page, thus all 4 actively listening UI apps would open the web page.

If it is only 1 of the UI's should be responding, then you need to identify the rule to pick which one, then I would still think the Service would be the right way to go, and the Service could determine which of the 4 based on the rules defined, should get the command to open the webpage.

In the end, I still wouldn't do that, opening applications on users without their involvement can end in bad data, i.e. they are typing away on the keyboard and not even looking at the monitor and all of a sudden realize they have been typing into the wrong form for the last 4 enter presses, thinking they were typing an email. You sure Task-bar notifications isn't a better idea? You could make them as Intrusive as you wanted.