6

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

TcpClient server = new TcpClient();
server.Connect(IPAddress.Parse(ip), 10001);
server.GetStream().BeginRead(buffer, 0, buffer.Length, new AsyncCallback(DataReceived), server.GetStream());

它从另一个线程调用以下方法:

 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

我也尝试过如下实现断开连接的方法:

server.GetStream().Close();

但这会导致以下错误:

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

我认为这与已调用 BeginRead() 方法而未调用 EndRead() 方法这一事实有关。如果是这种情况,我怎样才能在不崩溃的情况下关闭流?

4

1 回答 1

1

我只会调用GetStream一次并将结果存储在某处并使用它来访问流。

Stream nstrm = server.GetStream();

用于nstrm所有访问NetworkStream...

最安全的方法是维护一个关闭标志并将该标志设置为disconnect().

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

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

请参阅http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.getstream.aspx

编辑 - 根据评论:

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

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

于 2011-08-17T14:08:08.570 回答