如果在套接字关闭后调用 Socket.BeginSend,则应用程序崩溃而不引发异常
我正在编写一个套接字应用程序,它可以同时异步轮询多个服务器并向用户报告其状态的任何变化。到目前为止,一切正常,除了一个我似乎无法弄清楚的小错误。
服务器每 10 秒创建一组套接字,然后调用异步连接。然后由 ProcessConnectionComplete(IAsyncResult iar) 方法处理,该方法随后调用 Socket.BeginReceive 和 Socket.Begin send。然后使用另一种方法处理任何接收到的数据。
然后,在创建下一波套接字之前的 10 秒结束时,任何尚未接收到数据并关闭的套接字将被循环强制关闭。
我遇到的问题是,如果套接字恰好在调用 Socket.BeginSend 方法之前关闭(即有人通过网络电缆绊倒,或者另一端的服务器崩溃),程序将毫无例外地退出(错误代码 0 ),当它应该抛出异常时。代码如下:
private static void ProcessConnectionComplete(IAsyncResult iar)
{
SocketState state = iar.AsyncState as SocketState;
if (state.Socket.Connected)
{
// start waiting for a reply
state.Socket.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, new AsyncCallback(frm_Server_Poll.ProcessAsyncReceive), state);
//state.Socket.Close(); // if socket is closed after .Connected check and before BeginSend, crash occurs
try
{
// send message
state.Socket.BeginSend(new byte[] { (byte)'\xfe' }, 0, 1, SocketFlags.None, null, state);
}
catch (Exception ex) // Never called, EXCEPTION WHERE ARE YOU???
{
throw (ex);
}
}
else
{
state.ServerInfo.connected = false;
}
}
为什么会发生这种情况?我有一些想法,这与异步调用处理线程的方式有关,但不知道如何捕获异常。任何帮助将不胜感激。
I'm writing a socket application that asynchronously polls several servers at once and reports any changes in their states to the user. So far everything is working, except for one small bug I can't seem to figure out.
The server creates a bunch of sockets every 10 seconds, then calls an async connect. This is then handled by a ProcessConnectionComplete(IAsyncResult iar) method, which then calls both Socket.BeginReceive and then Socket.Begin send. Any received data is then handled with another method.
Then, at the end of the 10 seconds before the next wave of sockets is created, any sockets that have not already received data and closed are forcefully closed by a loop.
The issue I am having is that if the socket happens to close just before the Socket.BeginSend method is called (ie someone trips over a network cable, or the server on the other end crashes), the program exits without exeption (error code 0), when it should throw an exception. Here's the code:
private static void ProcessConnectionComplete(IAsyncResult iar)
{
SocketState state = iar.AsyncState as SocketState;
if (state.Socket.Connected)
{
// start waiting for a reply
state.Socket.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, new AsyncCallback(frm_Server_Poll.ProcessAsyncReceive), state);
//state.Socket.Close(); // if socket is closed after .Connected check and before BeginSend, crash occurs
try
{
// send message
state.Socket.BeginSend(new byte[] { (byte)'\xfe' }, 0, 1, SocketFlags.None, null, state);
}
catch (Exception ex) // Never called, EXCEPTION WHERE ARE YOU???
{
throw (ex);
}
}
else
{
state.ServerInfo.connected = false;
}
}
Why is this happening? I have some idea that it is to do with the way threading is handled with Async calls, but have no idea how to catch the exception. Any help would be greatly appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
调用
Socket.EndReceive
时,异常应该发生在回调 (frm_Server_Poll.ProcessAsyncReceive
) 中。同样,对于发送,调用
Socket.EndSend
时的回调中应该发生异常。但是,您的BeginSend
没有用于处理错误的回调。我不能确定,但我怀疑这就是异常神秘丢失的原因。
值得注意的是,如果调用时套接字已被释放,则
BeginReceive
和BeginSend
都可以直接抛出异常。The exception should occur in the callback (
frm_Server_Poll.ProcessAsyncReceive
) when callingSocket.EndReceive
.Likewise, for the send, the exception should occur in its callback when calling
Socket.EndSend
. However, yourBeginSend
does not have a callback with which to handle errors.I cannot be certain, but I suspect that this is why the exception is getting mysteriously lost.
It's worth noting that both
BeginReceive
andBeginSend
can throw directly if the socket is disposed at the time they are called.我不明白。这些事件都不会关闭您的套接字。只有您可以关闭套接字。这些事件可以中止连接,在这种情况下,您的发送将收到 ECONNRESET 在 C# 中映射到的任何异常。如果您自己关闭套接字然后发送,如果 C# 中没有其他内容先捕获它,您将获得 EBADF 映射到的任何内容。
I do not understand. Neither of those events will close your socket. Only you can close your socket. Those events can abort the connection, in which case your send will get whatever exception an ECONNRESET maps to in C#. If you close the socket yourself and then send, you will get whatever EBADF maps to if nothing else in C# traps it first.