locked
Windows Service in C# Start Failed RRS feed

  • Question

  • Hello Everyone,

    I have a windows service written in C# that is using TcpListener to listen requests from clients. Service is installed successfully, but when i am trying to run it's giving me error message 

    Here is code in OnStart Method

    protected override void OnStart(string[] args)
            {
                TcpListener serverSocket = new TcpListener(8888);
                TcpClient clientSocket = default(TcpClient);
                serverSocket.Start();
                Library.WriteErrorLog("Server Started");
                clientSocket = serverSocket.AcceptTcpClient();
                Library.WriteErrorLog("Ready to Accept");
    
                while ((true))
                {
                    try
                    {
                        NetworkStream networkStream = clientSocket.GetStream();
                        string dataFromClient;
                        byte[] bytesFrom = new byte[10025];
    
                        if (networkStream.DataAvailable)
                        {
                            networkStream.Read(bytesFrom, 0, 100);
                            dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom);
                            dataFromClient = dataFromClient.Substring(0, dataFromClient.IndexOf('\0'));
    
                            Library.WriteErrorLog("Data from Client" + dataFromClient);
                            networkStream.Flush();
                        }
                    }
                    catch (Exception ex)
                    {
                        Library.WriteErrorLog(ex.Message.ToString() + " | Exception in Main");
                    }
                }
            }
    

    What could be possible reason of this error. please guide.


    Jazaib Hussain

    Saturday, June 30, 2018 12:50 AM

All replies

  • The answer is in the error message.  Move the network processing out of the OnStart method so that it returns to the service controller without delay.  It should probably be in a separate thread.

    • Edited by RLWA32 Saturday, June 30, 2018 2:00 AM
    Saturday, June 30, 2018 1:59 AM
  • Services in their OnStart method must return back to the SCM within a small amount of time. If they do not then the SCM considers the service non responsive and shuts it down. All work in a service must be done on a secondary thread. The OnStart is used to start that work. 

    Move all your logic into a background thread other than perhaps any validation that your service can do anything at all. In the OnStart create and run the background thread. In your OnStop method set a sync object (event or something) to tell the thread to terminate and then block until it does or the SCM stops your service anyway.

    //Example only
    private Thread _thread;
    private ManualResetEvent _terminate = new ManualResetEvent(false);
    
    protected override void OnStart(string[] args)
    {
       _thread = new Thread(ListenForMessages);
       _thread.IsBackground = true;
       _thread.Start();
    }
    
    protected override void OnStop ()
    {
       _terminate.Set();
       if (!_thread.Join(5000))
          _thread.Kill();
    
       _thread = null;
    }
    
    private void ListenForMessages ()
    {   
      TcpListener serverSocket = new TcpListener(8888);
      TcpClient clientSocket = default(TcpClient);
      serverSocket.Start();
      Library.WriteErrorLog("Server Started");
      clientSocket = serverSocket.AcceptTcpClient();
      Library.WriteErrorLog("Ready to Accept");
    
      while (!_terminate.WaitOne())
      {
         …
      }
    }


    Michael Taylor http://www.michaeltaylorp3.net

    Saturday, June 30, 2018 4:37 AM
  • Thanks for you response. It's working fine for me but accepting just one request. Do i need to restart my service again and again to get multiple requests from client ?

    Jazaib Hussain

    Saturday, June 30, 2018 1:09 PM
  • Show your new code now ... it's probably not the same code that Michael posted.  ;0)

    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Saturday, June 30, 2018 4:39 PM
  • In your original listener code you only accept a single client. The call to AcceptTcpClient gets a single connection. Thereafter you're looping and reading data from them. To accept multiple clients you have to move the actual client processing to a separate thread. In your listener thread you'd just accept the connection, spawn the thread and then continue listening again on the original thread. This allows any # of clients (up to resource limits) to connect and each one will be handled by its own thread. But that discussion should be a separate question. There are also many posts on this topic already in the forums so you should be able to find an existing example.

    Note also that it is generally recommend that you create your service to run as both a console and service. The changes are minimal and there are third party libraries like TopShelf to help with this. This would allow you to write and debug your code normally and then "convert" it to a service. Beyond the lifetime and security aspects of services, they behave a lot like a console app. I blogged about this a few years ago if you're interested.


    Michael Taylor http://www.michaeltaylorp3.net

    Saturday, June 30, 2018 6:22 PM
  • Hi Jazaib,

    Michael's suggestion that you create your service to run as both a console and a service, is a good one. In addition to his blog post that he linked to, please take a look at my blog post that I wrote about the same topic a few years ago also:

    https://geek-goddess-bonnie.blogspot.com/2013/10/easy-windows-services.html

    It kind of complements Michael's blog post.  :0)


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Saturday, June 30, 2018 10:05 PM
  • using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.SqlClient; using System.Diagnostics; using System.Linq; using System.Net.Sockets; using System.ServiceProcess; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; namespace QueueManager { public partial class Scheduler : ServiceBase { private Thread _thread; private ManualResetEvent _terminate = new ManualResetEvent(false); SqlConnection sqlConnection = new SqlConnection(Constants.DATABASE_CONNECTION); SqlCommand sqlCommand; SqlDataReader sqlDataReader; public Scheduler() { InitializeComponent(); } protected override void OnStart(string[] args) { _thread = new Thread(ListenForMessages); _thread.IsBackground = true; _thread.Start(); Library.WriteErrorLog("Services Started"); } private void ListenForMessages(object obj) { TcpListener serverSocket = new TcpListener(8888); TcpClient clientSocket = default(TcpClient); serverSocket.Start(); Library.WriteErrorLog("Server Started"); clientSocket = serverSocket.AcceptTcpClient(); Library.WriteErrorLog("Ready to Accept"); while (!_terminate.WaitOne()) { try { NetworkStream networkStream = clientSocket.GetStream(); string dataFromClient; byte[] bytesFrom = new byte[10025];

    if (networkStream.DataAvailable) { networkStream.Read(bytesFrom, 0, 100); dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom); dataFromClient = dataFromClient.Substring(0, dataFromClient.IndexOf('\0')); Library.WriteErrorLog("Data from Client :" + dataFromClient); networkStream.Flush(); } } catch (Exception ex) { Library.WriteErrorLog(ex.ToString() + " | Exception in Main"); } } } protected override void OnStop() { _terminate.Set(); if (!_thread.Join(5000)) _thread.Abort(); _thread = null; }

    Here is my updated code as per @Michael suggestion. Where to change it to accept multiple requests. I am also trying to get knowledge about to run a server as both console and service. But for the time being i need to use this. Kindly update me on this.


    Jazaib Hussain

    Saturday, June 30, 2018 10:47 PM
  • Any Update on my thread as i have updated my code and posted it here. please check and let me know about it???

    Jazaib Hussain


    Monday, July 2, 2018 12:05 PM
  • You have to move the actual client logic out of your worker thread.

    //This won't compile, you'll have to fix the compiler errors
    private List<Thread> _clients = new List<Thread>();
    
    private void ListenForMessages(object obj)
    {
       TcpListener serverSocket = new TcpListener(8888);
       TcpClient clientSocket = default(TcpClient);
       serverSocket.Start();
       Library.WriteErrorLog("Server Started");
       
       //Loop waiting for more clients
       while (!_terminate.WaitOne())
       {
          //Note that this is a blocking call which means the
          //thread won't actually properly listen for a 
          //termination request - consider using async/await
          //instead
          clientSocket = serverSocket.AcceptTcpClient();
          Library.WriteErrorLog("Ready to Accept");
    
          //Start child thread to process request
          var childThread = new Thread(HandleClient);
          childThread.IsBackground = true;
          childThread.Start(clientSocket);
       };
    }
    
    private void HandleClient ( Socket socket )
    {
       while (!_terminate.WaitOne())
       {
          //Process client requests
       };
    }
    Your OnStop method, by setting the event would terminate all the clients but you'd probably want to verify they terminate before your OnStop finishes. Of course if the service is stopping then they will be auto-terminated anyway so it might not matter.


    Michael Taylor http://www.michaeltaylorp3.net

    Monday, July 2, 2018 2:06 PM