2

リモートホストに接続し、メッセージを送信し、返信を受け取り、情報を使用するいくつかの異なる方法があります。これは、接続クラスの同じインスタンスで 2 つのメソッドを使用するまでうまくいきました。エラーが発生している例では、次のメソッドを実行します。

public string sendRequestAccountID(string siteID)
{
    //build message
    String response = String.Empty;

    TcpClient client = new TcpClient();
    client.Connect(detailsHere);
    NetworkStream stream = client.GetStream();

    StreamWriter writer = new StreamWriter(stream);
    writer.AutoFlush = false;

    writer.WriteLine(sb.ToString());
    writer.Flush();

    StreamReader reader = new StreamReader(stream);
    List<XmlNode> nodeList = new List<XmlNode>();

    byte[] responseBytes = new byte[4096];
    int bytesRead = 0;

    while (true)
    {
        bytesRead = stream.Read(responseBytes, 0, responseBytes.Length);
        if (bytesRead > 0)
        {
            //handle message
        }
        if (bytesRead == 0)
        {
            stream.Flush();
            stream.Close();
            client.Close();
            string finalResponse = stuffHereToSend;
            return finalResponse;
        }
    }
}

これは問題なく送信され、期待どおりにメッセージが返されます。ただし、接続クラスの同じインスタンスを使用し、次のメソッドを使用するとします。

public bool sendNewDevice(IDeviceInterface device)
{
    NetworkStream stream;
    sb = new StringBuilder();
    //build message
    String response = String.Empty;

    TcpClient client = new TcpClient();
    client.Connect(detailsHere);
    stream = client.GetStream();

    StreamWriter writer = new StreamWriter(stream);
    writer.AutoFlush = false;

    writer.WriteLine(sb.ToString());
    writer.Flush();

    StreamReader reader = new StreamReader(stream);
    List<XmlNode> nodeList = new List<XmlNode>();

    byte[] responseBytes = new byte[4096];
    int bytesRead = 0;

    while (true)
    {
        bytesRead = stream.Read(responseBytes, 0, responseBytes.Length);
        if (bytesRead > 0)
        { 
            //handle message
        }
    }
}

「破棄されたオブジェクトにアクセスできません」というエラーが表示されます。

 bytesRead = stream.Read(responseBytes, 0, responseBytes.Length);

最新の方法で新しくストリームを割り当てただけだと思っていましたが。以前に閉じたものを使用しようとしていますか? これを回避する方法や、私が見逃しているばかげたものはありますか?

編集:クライアントが正しく処分していないことに何か関係がありますか?2 つのメソッドは互いに 1 秒以内に実行されます。最初のメソッドが閉じる前に 2 番目のメソッドを開こうとしている可能性がありますか?

4

1 に答える 1

6

StreamWriter(およびリーダー) が閉じられるか、そのメソッドDisposeが呼び出されると、基になるストリームが破棄されます。.net 4.5より前は、指定されたStreamWriterto をラップしてへの呼び出しを無視するクラス以外のものを使用するか、クラスを作成する以外に、実際にできることは何もありませんでした。.NET 4.5 では、指定したストリームを破棄しないように に指示するために使用できるオーバーロードがあります。例: 新しいStreamStreamWriterDisposeStreamWriterStreamWriter(stream, StreamWriter.UTF8NoBOM, 1024, false)

ラップされたストリームを使用してクローズを無視することができます (呼び出しnew StreamWriter(new NonDisposableStreamWrapper(stream))):

public class NonDisposableStreamWrapper : Stream
{
    private Stream wrappedStream;

    public NonDisposableStreamWrapper(Stream wrappedStream)
    {
        this.wrappedStream = wrappedStream;
    }

    public override void Flush()
    {
        wrappedStream.Flush();
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        return wrappedStream.Seek(offset, origin);
    }

    public override void SetLength(long value)
    {
        wrappedStream.SetLength(value);
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        return wrappedStream.Read(buffer, offset, count);
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        wrappedStream.Write(buffer, offset, count);
    }

    public override bool CanRead
    {
        get { return wrappedStream.CanRead; }
    }

    public override bool CanSeek
    {
        get { return wrappedStream.CanSeek; }
    }

    public override bool CanWrite
    {
        get { return wrappedStream.CanWrite; }
    }

    public override long Length
    {
        get { return wrappedStream.Length; }
    }

    public override long Position
    {
        get { return wrappedStream.Position; }
        set { wrappedStream.Position = value; }
    }
}
于 2012-07-31T14:07:11.000 に答える