C# 应用程序在关机时不退出(有时)
我的应用程序可以防止窗口关闭,但仅限于某些计算机,而不是始终如此。调试起来有点棘手。 我认为这是由于我的 TCP 服务器造成的。它是一个异步服务器,我的应用程序处理 CloseReason == WindowsShutDown。 发生这种情况时,我的应用程序仍然作为进程运行,但无法从任务栏/系统托盘访问。
我想知道是否有人能看到我的服务器代码有任何明显的问题。
下面是我的服务器的代码。 Stop() 方法是从主窗体 Close() 事件中调用的。
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 调用在数据报套接字上发送时) ) 未提供地址。
还不完全确定这意味着什么。
My application prevents windows shutting down, but only on some computers, and not all the time. Its a little tricky to debug.
I think its due to my TCP server. It is an asynchronous server, and my application handles the CloseReason == WindowsShutDown.
When this occurs, my application is still running as a process, but is not accessible from taskbar/system tray.
I was wondering if anyone can see any obvious issues with my server code.
Below is the code for my server. The Stop() method is called from the main forms Close() event.
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);
}
}
EDIT
Thanks to Hogan, some more information on the call to Close():
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied.
Not entirely sure what this means yet.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您必须向 Windows 事件日志添加一些日志记录才能查看发生了什么。
最好的起点是返回 false 的 catch(因为这将阻止 Windows 关闭)。如果您在那里记录原因,那么至少您可以查看事件日志以了解为什么您的服务不会关闭。
You have to add some logging to the windows event log to see what is going on.
The best place to start is in the catch that returns false (since this will stop windows from shutting down.) If you log the reason there then at least you can look at the event log to see why your service won't shut down.
您应该始终确保在回调发生时调用任何异步方法的 EndXXX 对应方法。您无法执行此操作:
因为它位于
!shuttingDown
块中。调用它...捕获错误。You should always ensure that you call the EndXXX counterpart method for any async method when the callback occurs. You fail to do this for:
because it lives in a
!shuttingDown
block. Call it... catch the error.