关闭 TcpClient 后如何避免 ObjectDisposed 异常
How to avoid ObjectDisposed exception after closing TcpClient
我在 TcpClient
上有待处理的 ReadAsync
操作。
我的应用程序在确定不可能再进行通信时关闭 TcpClient
。在套接字上调用 TcpClient.Close
会导致 Exception thrown: 'System.ObjectDisposedException' in mscorlib.dll
被先前对 ReadAsync()
.
的调用抛出
如何避免这种异常?
最小示例:(使用putty、nc等打开连接进行测试)
using System;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;
using System.Threading.Tasks;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private TcpClient client;
// Initialize the form
public Form1()
{
InitializeComponent();
}
// Start the Listen() task when the form loads
private void Form1_Load(object sender, EventArgs e)
{
var task = Listen();
}
// Listen for the connection
public async Task Listen()
{
// Start the listener
var listener = new TcpListener(IPAddress.Any, 80);
listener.Start();
// Accept a connection
client = await listener.AcceptTcpClientAsync();
// Wait for some data (the client doesn't send any for the sake of reproducing the issue)
// An exception is generated in 'ReadAsync' after Button1 is clicked
byte[] buffer = new byte[100];
await client.GetStream().ReadAsync(buffer, 0, 100);
}
// I will click this button before the above call to `ReadAsync` receives any data
private void button1_Click_1(object sender, EventArgs e)
{
// This causes an exception in the above call to `ReadAsync`
client.Close();
}
}
}
CancellationToken can't be used取消ReadAsync()
。有没有办法在不抛出异常的情况下关闭与挂起的 ReadAsync()
的连接?除非绝对必要,否则我不想在这里使用 try/catch
。
我已经实现了一个使用 TCPClient 侦听 TCP 端口的应用程序,而不是使用 Task Listen() 函数为什么不使用 while 循环来保持连接打开,那么您可以在 while 循环中使用一些条件在满足您的要求时关闭连接...
调用 Socket.Shutdown()
允许连接正常关闭,从而根据需要从 ReadAsync()
到 return 0
。
然后可以在 ReadAsync()
returns 0
.
之后调用 TcpClient.Close()
来处理套接字对象
// Listen for the connection
public async Task Listen()
{
// ...
// Wait for some data (the client won't be sending any at this point)
byte[] msgBuf = new byte[100];
var lengthRead = await client.GetStream().ReadAsync(msgBuf, 0, 100);
if (lengthRead == 0)
{
// A graceful shutdown has occurred. The socket can now be disposed
// by "TcpClient.Close()"
client.Close();
}
}
// I will click this button to close the connection before the above call to `ReadAsync` receives any data
private void button1_Click_1(object sender, EventArgs e)
{
// This causes ReadAsync() to return 0 after which the socket can be disposed
client.Client.Shutdown(SocketShutdown.Both);
}
我在 TcpClient
上有待处理的 ReadAsync
操作。
我的应用程序在确定不可能再进行通信时关闭 TcpClient
。在套接字上调用 TcpClient.Close
会导致 Exception thrown: 'System.ObjectDisposedException' in mscorlib.dll
被先前对 ReadAsync()
.
如何避免这种异常?
最小示例:(使用putty、nc等打开连接进行测试)
using System;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;
using System.Threading.Tasks;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private TcpClient client;
// Initialize the form
public Form1()
{
InitializeComponent();
}
// Start the Listen() task when the form loads
private void Form1_Load(object sender, EventArgs e)
{
var task = Listen();
}
// Listen for the connection
public async Task Listen()
{
// Start the listener
var listener = new TcpListener(IPAddress.Any, 80);
listener.Start();
// Accept a connection
client = await listener.AcceptTcpClientAsync();
// Wait for some data (the client doesn't send any for the sake of reproducing the issue)
// An exception is generated in 'ReadAsync' after Button1 is clicked
byte[] buffer = new byte[100];
await client.GetStream().ReadAsync(buffer, 0, 100);
}
// I will click this button before the above call to `ReadAsync` receives any data
private void button1_Click_1(object sender, EventArgs e)
{
// This causes an exception in the above call to `ReadAsync`
client.Close();
}
}
}
CancellationToken can't be used取消ReadAsync()
。有没有办法在不抛出异常的情况下关闭与挂起的 ReadAsync()
的连接?除非绝对必要,否则我不想在这里使用 try/catch
。
我已经实现了一个使用 TCPClient 侦听 TCP 端口的应用程序,而不是使用 Task Listen() 函数为什么不使用 while 循环来保持连接打开,那么您可以在 while 循环中使用一些条件在满足您的要求时关闭连接...
调用 Socket.Shutdown()
允许连接正常关闭,从而根据需要从 ReadAsync()
到 return 0
。
然后可以在 ReadAsync()
returns 0
.
TcpClient.Close()
来处理套接字对象
// Listen for the connection
public async Task Listen()
{
// ...
// Wait for some data (the client won't be sending any at this point)
byte[] msgBuf = new byte[100];
var lengthRead = await client.GetStream().ReadAsync(msgBuf, 0, 100);
if (lengthRead == 0)
{
// A graceful shutdown has occurred. The socket can now be disposed
// by "TcpClient.Close()"
client.Close();
}
}
// I will click this button to close the connection before the above call to `ReadAsync` receives any data
private void button1_Click_1(object sender, EventArgs e)
{
// This causes ReadAsync() to return 0 after which the socket can be disposed
client.Client.Shutdown(SocketShutdown.Both);
}