【问题标题】:C# Application not exiting on Shutdown (sometimes)C# 应用程序在关机时不退出(有时)
【发布时间】:2011-04-29 01:14:17
【问题描述】:

我的应用程序可以防止 Windows 关闭,但仅限于某些计算机,并非一直如此。调试起来有点棘手。 我认为这是由于我的 TCP 服务器。它是一个异步服务器,我的应用程序处理 CloseReason == WindowsShutDown。 发生这种情况时,我的应用程序仍作为进程运行,但无法从任务栏/系统托盘访问。

我想知道是否有人可以看到我的服务器代码有任何明显的问题。

以下是我的服务器的代码。从主窗体的 Close() 事件调用 Stop() 方法。

public class MantraServer
    {
        protected int portNumber;
        private bool ShuttingDown = false;

        //the main socket the server listens to
        Socket listener;

        //Constructor - Start a server on the given IP/port
        public MantraServer(int port, IPAddress IP)
        {
            this.portNumber = port;
            Start(IP);
        }

        /// 
        /// Description: Start the threads to listen to the port and process
        /// messages.
        ///
        public void Start(IPAddress IP)
        {
            try
            {
                //We are using TCP sockets
                listener = new Socket(AddressFamily.InterNetwork,
                                          SocketType.Stream,
                                          ProtocolType.Tcp);

                //Assign the any IP of the machine and listen on port number 3000
                IPEndPoint ipEndPoint = new IPEndPoint(IP, 3000);

                //Bind and listen on the given address
                listener.Bind(ipEndPoint);
                listener.Listen(10);

                //Accept the incoming clients
                listener.BeginAccept(new AsyncCallback(OnAccept), listener);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "MANTRA Network Start Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// Decription: Stop the threads for the port listener.
        public bool Stop()
        {
            try
            {
                ShuttingDown = true;
                listener.Shutdown(SocketShutdown.Both);
                listener.Close();
                listener = null;
                System.Threading.Thread.Sleep(500); //wait for half second while the server closes
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// 
        /// Decription: Call back method to accept new connections.
        /// <param name="ar">Status of an asynchronous operation.</param>
        private void OnAccept(IAsyncResult ar)
        {
            try
            {
                if (!ShuttingDown)
                {
                    MantraStatusMessage InMsg = new MantraStatusMessage();
                    InMsg.Socket = ((Socket)ar.AsyncState).EndAccept(ar);
                    //Start listening for more clients
                    listener.BeginAccept(new AsyncCallback(OnAccept), listener);

                    //Once the client connects then start receiving the commands from them
                    InMsg.Socket.BeginReceive(InMsg.buffer, 0, InMsg.buffer.Length, SocketFlags.None,
                        new AsyncCallback(OnReceive), InMsg);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "MANTRA Network Accept Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        ///  
        /// Receives the data, puts it in a buffer and checks if we need to receive again.  
        public void OnReceive(IAsyncResult result)
        {
            MantraStatusMessage InMsg = (MantraStatusMessage)result.AsyncState;
            int read = InMsg.Socket.EndReceive(result);
            if (read > 0)
            {
                for (int i = 0; i < read; i++)
                {
                    InMsg.TransmissionBuffer.Add(InMsg.buffer[i]);
                }
                //we need to read again if this is true  
                if (read == InMsg.buffer.Length)
                {
                    InMsg.Socket.BeginReceive(InMsg.buffer, 0, InMsg.buffer.Length, SocketFlags.None, OnReceive, InMsg);
                    Console.Out.WriteLine("Message Too big!");
                }
                else
                {
                    Done(InMsg);
                }
            }
            else
            {
                Done(InMsg);
            }
        }

        ///  
        /// Deserializes and outputs the received object  
        public void Done(MantraStatusMessage InMsg)
        {
            Console.Out.WriteLine("Received: " + InMsg.msg);
            MantraStatusMessage received = InMsg.DeSerialize();
            Console.WriteLine(received.msg.Message);
        }
    }

编辑

感谢 Hogan,提供有关 Close() 调用的更多信息:

由于未连接套接字并且(在使用 sendto 调用在数据报套接字上发送时)未提供地址,因此不允许发送或接收数据的请求。

还不完全确定这意味着什么。

【问题讨论】:

    标签: c# multithreading sockets system-shutdown


    【解决方案1】:

    您必须在 Windows 事件日志中添加一些日志记录才能查看发生了什么。

    最好的起点是返回 false 的 catch(因为这将阻止 Windows 关闭。)如果您在那里记录原因,那么至少您可以查看事件日志以了解您的服务为什么不会关闭关闭。

    【讨论】:

    • 感谢 Hogan - 看起来 listener.ShutDown() 调用正在生成异常。我不明白为什么会这样?在测试期间,应该没有数据发送或接收,但这个调用仍然会产生一个错误,就像我上面的编辑一样......
    • 你能把抛出错误的语句包装成类似 `if (listener.connected) listener.ShutDown();' 的语句吗?
    • 是的,我尝试了 Disconnect() 但未连接套接字。现在我正在尝试有条件的 ShutDown()。看看这是否能解决我的问题。干杯
    【解决方案2】:

    您应该始终确保在回调发生时为任何异步方法调用 EndXXX 对应方法。你没有这样做:

    InMsg.Socket = ((Socket)ar.AsyncState).EndAccept(ar);
    

    因为它位于!shuttingDown 块中。调用它...捕获错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多