C# 在C中调用BeginRead()后关闭网络流#

C# 在C中调用BeginRead()后关闭网络流#,c#,asynchronous,networkstream,C#,Asynchronous,Networkstream,我实现了一个系统,它模拟串行端口的DataReceived事件,通过使用BeginRead()方法触发从TCPClient对象的网络流读取数据,如下所示: TcpClient server = new TcpClient(); server.Connect(IPAddress.Parse(ip), 10001); server.GetStream().BeginRead(buffer, 0, buffer.Length, new AsyncCallback(DataReceived), serv

我实现了一个系统,它模拟串行端口的DataReceived事件,通过使用BeginRead()方法触发从TCPClient对象的网络流读取数据,如下所示:

TcpClient server = new TcpClient();
server.Connect(IPAddress.Parse(ip), 10001);
server.GetStream().BeginRead(buffer, 0, buffer.Length, new AsyncCallback(DataReceived), server.GetStream());
server.GetStream().Close();
它从另一个线程调用以下方法:

 private void DataReceived(IAsyncResult result)
    {
        res = result;
        server.GetStream().EndRead(result);

        //append received data to the string buffer
        stringBuffer += System.Text.ASCIIEncoding.ASCII.GetString(buffer);

        //clear the byte array
        Array.Clear(buffer, 0, buffer.Length);

        //trigger the parser
        waitHandle.Set();

        server.GetStream().BeginRead(buffer, 0, buffer.Length, new AsyncCallback(DataReceived), buffer);
    }
这似乎工作正常。我可以毫无问题地向网络上的设备发送和接收数据。但是,当我尝试使用以下方法断开连接时,程序崩溃:

public override void disconnect()
{
    server.Close();
}
它抛出以下错误:

A first chance exception of type 'System.ObjectDisposedException' occurred in System.dll
A first chance exception of type 'System.InvalidOperationException' occurred in System.dll
我还尝试实现断开连接方法,如下所示:

TcpClient server = new TcpClient();
server.Connect(IPAddress.Parse(ip), 10001);
server.GetStream().BeginRead(buffer, 0, buffer.Length, new AsyncCallback(DataReceived), server.GetStream());
server.GetStream().Close();
但这会导致以下错误:

A first chance exception of type 'System.ObjectDisposedException' occurred in System.dll
A first chance exception of type 'System.InvalidOperationException' occurred in System.dll

我假设这与BeginRead()方法已被调用而EndRead()方法未被调用有关。如果是这样的话,我如何才能关闭流而不使其崩溃呢?

我只会调用
GetStream
一次,然后将结果存储在某个地方,并使用它访问流

Stream nstrm = server.GetStream();
网络流的所有访问使用
nstrm

最安全的方法是维护一个关闭标志,只需在
disconnect()
中设置该标志

DataReceived
中,您将在
EndRead
之后直接检查该标志,如果设置了该标志,则执行以下操作:

server.Close();
nstrm.Close();

编辑-根据评论:

if (flag2Close)
{
    server.Close();
    nstrm.Close();
    flag2Close = false;
}
else
{
    nstrm.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(DataReceived), buffer);
}

顺便说一句:对于生产代码,它需要一些异常处理等。

这是可行的,但是,由于在调用EndRead()后会检查标志,因此必须先接收数据,然后才能终止连接。所以,如果我连接,断开连接,然后再次连接,它会抛出一个错误,因为连接从未关闭过。如果我连接,断开连接,发送一些数据,然后再连接,它会工作。我不确定我是否理解。。。处理标志以关闭TcpClient和流的位置完全取决于您-您甚至可以将检查直接放在下一个起始点之前,并且只有在标志为false时才执行起始点。。。请参见上面的编辑是的,但是当调用BeginRead()方法时,它会回调方法DataReceived并阻塞,直到收到数据为止。这意味着在方法的下一次迭代(在接收数据时发生)之前不会检查该标志。您可以使用带有超时的WaitHandle—这样您就不需要等到真正接收到数据—对于代码示例,请参见您需要在EndRead()调用周围使用一个try块,以便捕获ObjectDisposedException。这是插座意外关闭的可靠指示器。我发现了问题。我得到了一个
“System.ObjectDisposedException”
,因为EndRead()和BeginRead()方法调用没有被try/catch块包围。当我关闭流时,这些方法试图在一个不再存在的对象上执行。检查这些答案,它们的问题是相同的: