尽管异常类型的 catch 块异常升级
Exception escalates despite a catch block of Exceptions type
我有一个要写入数据的 TCP 套接字列表。如果写入失败,我将其从列表中删除并继续。
至少计划是这样。发生的情况是,当客户端断开连接时,SocketException 升级并且程序崩溃,即使该异常已被处理。代码如下:
// sockets is type List<Socket>
foreach (Socket s in sockets)
{
String jsonString = skeleton.Marshall();
byte[] jsonBytes = System.Text.Encoding.UTF8.GetBytes(jsonString);
try
{
s.Send(jsonBytes); // boom! System.Net.Sockets.SocketException!
}
catch (System.Net.Sockets.SocketException except)
{
sockets.Remove(s);
Console.WriteLine(except.StackTrace);
}
catch (Exception except)
{
Console.WriteLine(except.StackTrace);
}
}
我不明白为什么任何异常都可以通过这个。我没有看控制台输出,因为 Visual Studio 清除了异常发生时的内容(至少我在那里没有看到任何有意义的东西)
感谢您的帮助!
编辑
正如 Sebastian Negraszus 所指出的,我不能直接从列表中删除 Socket,所以现在的代码是
List<Socket> remove = new List<Socket>();
// sockets still is of type List<Socket>
foreach (Socket s in sockets)
{
String jsonString = skeleton.Marshall();
byte[] jsonBytes = System.Text.Encoding.UTF8.GetBytes(jsonString);
try
{
s.Send(jsonBytes);
}
catch (System.Net.Sockets.SocketException except)
{
remove.Add(s);
Console.WriteLine(except.StackTrace);
}
catch (Exception except)
{
Console.WriteLine(except.StackTrace);
}
}
foreach (Socket s in remove)
{
sockets.Remove(s);
}
但是,即使 Socket 没有从列表中删除,它也应该在这里升级。
编辑 2
此代码在事件处理程序中运行,而套接字正在主线程中填充,因此我认为缺少锁定会导致问题。但是加了锁之后,还是报错
主线程:
// ...
sockets = new List<Socket>();
delegateFoo += handlerFunction;
// ...
TcpListener tcpListener = new TcpListener(IPAddress.Any, 20001);
tcpListener.Start();
while (true) {
Socket s = tcpListener.AcceptSocket();
lock (sockets) {
sockets.Add(s);
}
}
处理函数:
// ...generate skeleton...
lock (sockets)
{
foreach (Socket s in sockets)
{
String jsonString = skeleton.Marshall();
byte[] jsonBytes = System.Text.Encoding.UTF8.GetBytes(jsonString);
try
{
s.Send(jsonBytes);
}
catch (System.Net.Sockets.SocketException except)
{
remove.Add(s);
Console.WriteLine(except.StackTrace);
}
catch (Exception except)
{
Console.WriteLine(except.StackTrace);
}
}
foreach (Socket s in remove)
{
sockets.Remove(s);
}
}
虽然运气不好,异常仍然升级(至少我是这么认为的,程序在 VS 中中断,这个小 window 出现说 "SocketException occured"(我使用德语版本,所以措辞可能不同)。
该错误可以通过使用腻子连接两次并关闭两个腻子之一来触发。下次调用 Send() 时 - boom.
编辑 3:异常详细信息
抱歉,这些是德语的。翻译:
- "... ist aufgetreten" = "...发生"
- "bei" = "at"
留言="An existing connection has been aborted/terminated by the host computer"
System.Net.Sockets.SocketException ist aufgetreten.
_HResult=-2147467259
_message=Eine bestehende Verbindung wurde softwaregesteuert durch den Hostcomputer abgebrochen
HResult=-2147467259
IsTransient=false
Message=Eine bestehende Verbindung wurde softwaregesteuert durch den Hostcomputer abgebrochen
Source=System
ErrorCode=10053
NativeErrorCode=10053
StackTrace:
bei System.Net.Sockets.Socket.Send(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
InnerException:
是的,我的程序中只发送了一次。
编辑 4:Visual Studio 古怪
好吧,Visual Studio 很奇怪。我可以取消选中 "break on Exceptions of this type" 复选框,然后它就会继续。所以异常并没有升级,但是还是让程序停止了。
我不明白你为什么要在默认情况下中断已处理的异常。我想如果我取消选中程序就会出错。如果您有更好的解决方案,我很乐意采纳您的回答。
我假设 sockets
是 List<T>
?当仍在 foreach
循环内时,您不能使用 sockets.Remove(s);
修改列表,因为这会使枚举器无效。下一次迭代导致 InvalidOperationException
.
取消选中 "break on exceptions of this type"(或任何英文名称)。之后工作正常。
我有一个要写入数据的 TCP 套接字列表。如果写入失败,我将其从列表中删除并继续。
至少计划是这样。发生的情况是,当客户端断开连接时,SocketException 升级并且程序崩溃,即使该异常已被处理。代码如下:
// sockets is type List<Socket>
foreach (Socket s in sockets)
{
String jsonString = skeleton.Marshall();
byte[] jsonBytes = System.Text.Encoding.UTF8.GetBytes(jsonString);
try
{
s.Send(jsonBytes); // boom! System.Net.Sockets.SocketException!
}
catch (System.Net.Sockets.SocketException except)
{
sockets.Remove(s);
Console.WriteLine(except.StackTrace);
}
catch (Exception except)
{
Console.WriteLine(except.StackTrace);
}
}
我不明白为什么任何异常都可以通过这个。我没有看控制台输出,因为 Visual Studio 清除了异常发生时的内容(至少我在那里没有看到任何有意义的东西)
感谢您的帮助!
编辑
正如 Sebastian Negraszus 所指出的,我不能直接从列表中删除 Socket,所以现在的代码是
List<Socket> remove = new List<Socket>();
// sockets still is of type List<Socket>
foreach (Socket s in sockets)
{
String jsonString = skeleton.Marshall();
byte[] jsonBytes = System.Text.Encoding.UTF8.GetBytes(jsonString);
try
{
s.Send(jsonBytes);
}
catch (System.Net.Sockets.SocketException except)
{
remove.Add(s);
Console.WriteLine(except.StackTrace);
}
catch (Exception except)
{
Console.WriteLine(except.StackTrace);
}
}
foreach (Socket s in remove)
{
sockets.Remove(s);
}
但是,即使 Socket 没有从列表中删除,它也应该在这里升级。
编辑 2
此代码在事件处理程序中运行,而套接字正在主线程中填充,因此我认为缺少锁定会导致问题。但是加了锁之后,还是报错
主线程:
// ...
sockets = new List<Socket>();
delegateFoo += handlerFunction;
// ...
TcpListener tcpListener = new TcpListener(IPAddress.Any, 20001);
tcpListener.Start();
while (true) {
Socket s = tcpListener.AcceptSocket();
lock (sockets) {
sockets.Add(s);
}
}
处理函数:
// ...generate skeleton...
lock (sockets)
{
foreach (Socket s in sockets)
{
String jsonString = skeleton.Marshall();
byte[] jsonBytes = System.Text.Encoding.UTF8.GetBytes(jsonString);
try
{
s.Send(jsonBytes);
}
catch (System.Net.Sockets.SocketException except)
{
remove.Add(s);
Console.WriteLine(except.StackTrace);
}
catch (Exception except)
{
Console.WriteLine(except.StackTrace);
}
}
foreach (Socket s in remove)
{
sockets.Remove(s);
}
}
虽然运气不好,异常仍然升级(至少我是这么认为的,程序在 VS 中中断,这个小 window 出现说 "SocketException occured"(我使用德语版本,所以措辞可能不同)。 该错误可以通过使用腻子连接两次并关闭两个腻子之一来触发。下次调用 Send() 时 - boom.
编辑 3:异常详细信息
抱歉,这些是德语的。翻译:
- "... ist aufgetreten" = "...发生"
- "bei" = "at"
留言="An existing connection has been aborted/terminated by the host computer"
System.Net.Sockets.SocketException ist aufgetreten. _HResult=-2147467259 _message=Eine bestehende Verbindung wurde softwaregesteuert durch den Hostcomputer abgebrochen HResult=-2147467259 IsTransient=false Message=Eine bestehende Verbindung wurde softwaregesteuert durch den Hostcomputer abgebrochen Source=System ErrorCode=10053 NativeErrorCode=10053 StackTrace: bei System.Net.Sockets.Socket.Send(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags) InnerException:
是的,我的程序中只发送了一次。
编辑 4:Visual Studio 古怪
好吧,Visual Studio 很奇怪。我可以取消选中 "break on Exceptions of this type" 复选框,然后它就会继续。所以异常并没有升级,但是还是让程序停止了。
我不明白你为什么要在默认情况下中断已处理的异常。我想如果我取消选中程序就会出错。如果您有更好的解决方案,我很乐意采纳您的回答。
我假设 sockets
是 List<T>
?当仍在 foreach
循环内时,您不能使用 sockets.Remove(s);
修改列表,因为这会使枚举器无效。下一次迭代导致 InvalidOperationException
.
取消选中 "break on exceptions of this type"(或任何英文名称)。之后工作正常。