how to close network stream connection properly? - c#

I have an application that is connecting to some network server (tcp) and is connected using a network stream:
if (!SSL)
{
_networkStream = new System.Net.Sockets.TcpClient(Server, Port).GetStream();
_StreamWriter = new System.IO.StreamWriter(_networkStream);
_StreamReader = new System.IO.StreamReader(_networkStream, Encoding.UTF8);
}
if (SSL)
{
System.Net.Sockets.TcpClient client = new System.Net.Sockets.TcpClient(Server, Port);
_networkSsl = new System.Net.Security.SslStream(client.GetStream(), false,
new System.Net.Security.RemoteCertificateValidationCallback(Protocol.ValidateServerCertificate), null);
_networkSsl.AuthenticateAsClient(Server);
_StreamWriter = new System.IO.StreamWriter(_networkSsl);
_StreamReader = new System.IO.StreamReader(_networkSsl, Encoding.UTF8);
}
///// since now I working with both reader and writer globally in multiple threads
I am using reader and writer asynchronously (in 2 threads) and I need to have both of these streams globally available (they are defined as public references on class level), so I don't know if using statement can be used here.
How should I properly close this connection? All objects (NetworkStream, stream writer and reader) have the Close() method. Should I call it for all of them? Or only 1 of them? Is there any need to release some resources?

Put them in a using block. It will close and dispose of each stream appropriately after the operation has been completed.
using (StreamReader reader = new StreamReader(_networkStream, Encoding.UTF8))
{
}

Use using() {} blocks. This way all Connections/streams are properly closed after usage.
using(_networkStream = new System.Net.Sockets.TcpClient(Server, Port).GetStream())
{
using(_StreamWriter = new System.IO.StreamWriter(_networkStream))
{
//do stuff
}
using(_StreamReader = new System.IO.StreamReader(_networkStream, Encoding.UTF8))
{
//do stuff
}
}

When they are disposed of, StreamReader and StreamWriter each dispose of the underlying NetworkStream automatically by default. Because of this, if you are using both a reader and a writer, you might get an "object already disposed" type of exception when you try to close the second one. I prefer to dispose of the stream itself but not the reader/writer since it's pointless in that case.
using stream = tcpClient.GetStream();
var reader = new StreamReader(stream);
var writer = new StreamWriter(stream);
// <use reader and writer>
// <the using statement ensures the stream is disposed of>
If you insist on disposing of the reader and writer, you can disable their default auto-close-the-stream behavior via the leaveOpen parameter:
new StreamReader(stream, leaveOpen: true)
new StreamWriter(stream, leaveOpen: true)
Making use of using is ideal if possible, but the other way to accomplish the same is to manually call the stream's Close() method or, equivalently, its Dispose() method.

Related

Memory stream closed?

How did the MemoryStream close when it has not reached the end of its using statement?
MusicDataStore musicData = MusicDataStore.TestData();
BinaryFormatter formatter = new BinaryFormatter();
using (MemoryStream memStream = new MemoryStream())
{
formatter.Serialize(memStream, musicData);
using (StreamReader reader = new StreamReader(memStream))
{
memStream.Position = 0;
Console.WriteLine(reader.ReadToEnd());
}
//deserialize
memStream.Position = 0;
MusicDataStore input = (MusicDataStore)formatter.Deserialize(memStream);
}
I should be able to deserialize the memStream but it cannot be read because it is closed.
When I tried removing the StreamReader block I can successfully deserialize the memStream. Why? What's happening to memStream in StreamReader block?
StreamReader takes ownership of the Stream it's given, and will close it when it is disposed (most of the types which take another IDisposable type in their constructor will do this).
This StreamReader constructor takes a boolean saying whether to leave the stream open after the StreamReader is disposed as its last parameter:
using (var reader = new StreamReader(memStream, Encoding.UTF8, true, 1024, true))
{
...
}
(Those other parameters are the defaults which StreamReader(Stream) uses, from the referencesource.)
As Marc Gravell rightly notes in the comments, we've said to use UTF-8 encoding, but it looks like your stream is binary and definitely not UTF-8 text! So expect this to fail in practice. It may be more useful to look at the output of BitConverter.ToString(memStream.GetBuffer(), 0, memStream.Length) (or more simply but less efficiently BitConverter.ToString(memStream.ToArray())).

Is there a benefit in closing StreamReader (or StreamWriter) when I close Stream explicitly?

I have the following code. In here I am using the StreamReader constructor with leaveOpen: true and in order to do that I need to give the previous parameters which I manage to get their default values. This is cumbersome. Since I use stream with using do I gain anything for using the StreamReader with using? Does answer change if it is a StreamWriter instead?
using (Strem stream = ...)
{
...
using (StreamReader sr = new StreamReader(stream, Encoding.UTF8, true, 1024, true))
{
...
}
...
}
What if any do I lose if use the following code instead?
using (Strem stream = ...)
{
...
StreamReader sr = new StreamReader(stream);
...
...
}
You do need to close a StreamWriter (generally via the using block), or else data in its buffer could be lost.
Because both StreamReader and StreamWriter default to closing the stream automatically, if you want to eliminate one using block from your code, it should be the Stream that you remove from using.
If you can't do that, for example you've borrowed the Stream from elsewhere that doesn't want you to close it, then you must use the leaveOpen parameter you're already aware of. The reason that you can't just omit the using statement for a StreamReader/StreamWriter in order to leave it open, is that the garbage collector will still trigger some cleanup (although not as much) since the object is unreachable... only this will now occur at an unrelated time, creating an unpredictable bug that's very hard to find.
It is indeed ugly that you can't specify leaveOpen without explicitly controlling the buffer size, etc. May I suggest a helper method along the lines of StreamReader CreateStreamReaderLeaveOpen(Stream)?
Because you have leaveOpen set to true in the constructor disposing of a StreamReader does nothing execpt call the the Dispose method of the TextReader class, which itself does nothing at all.
protected override void Dispose(bool disposing)
{
// Dispose of our resources if this StreamReader is closable.
// Note that Console.In should be left open.
try {
// Note that Stream.Close() can potentially throw here. So we need to
// ensure cleaning up internal resources, inside the finally block.
if (!LeaveOpen && disposing && (stream != null))
stream.Close();
}
finally {
if (!LeaveOpen && (stream != null)) {
stream = null;
encoding = null;
decoder = null;
byteBuffer = null;
charBuffer = null;
charPos = 0;
charLen = 0;
base.Dispose(disposing);
}
}
}
With a StreamWriter it does change a bit because it will not flush it's internal buffers to the underlying stream unless you dispose of the writer.

Why does StreamWriter need to be open to access my MemoryStream?

I have some test code that's preparing a MemoryStream that will eventually be read by an object. Here's how I want to write it:
var manager = new LeaderboardImportManager(leaderboard);
var columnNames = manager.ColumnNames;
var stream = new MemoryStream();
using (var writer = new StreamWriter(stream))
{
writer.WriteLine(string.Join(",", columnNames));
foreach (var user in users)
{
var row = leaderboard.Metrics.Select(m => Faker.RandomNumber.Next().ToString()).ToList();
row.Insert(0, user.UserName);
writer.WriteLine(string.Join(",", row));
}
writer.Flush();
stream.Position = 0;
}
return stream;
But when I do it that way, my stream object becomes unreadable and my test fails, so I have to do it like this:
var manager = new LeaderboardImportManager(leaderboard);
var columnNames = manager.ColumnNames;
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.WriteLine(string.Join(",", columnNames));
foreach (var user in users)
{
var row = leaderboard.Metrics.Select(m => Faker.RandomNumber.Next().ToString()).ToList();
row.Insert(0, user.UserName);
writer.WriteLine(string.Join(",", row));
}
writer.Flush();
stream.Position = 0;
return stream;
This, of course, prevents me from being able to dispose of my StreamWriter object, which as I understand it, should definitely be disposed of.
Why does the StreamWriter need to remain open if I've flushed its contents to the MemoryStream object already?
I can think of some very inconvenient ways to work around this, but I'd like to know why it doesn't work the way I want it, and whether or not there's something I can do to make it work that way. Any advice is appreciated, thanks!
By default, the StreamWriter "owns" the stream it is passed and will close it when disposed. Use the constructor that has a leaveOpen boolean parameter. Set it to true to avoid closing the underlying Stream when the writer is disposed in your first example.
StreamWriter automatically closes the Stream if you don't tell it not to. Create it like this instead to leave the Stream open:
using (var writer = new StreamWriter(stream, System.Text.Encoding.UTF8, 1024, true))
Alternatively, if you don't wish to pass the extra arguments, use GetBuffer to access MemoryStream's internal buffer. Avoid ToArray as this creates a copy of the data and depending on your scenario may be inefficient.
using operator calls Dispose method on object before exiting the operator block { }.
On disposal, StreamWriter disposes underlying Stream too.
This means your Stream is an invalidated object before it gets returned.
Apply using statement only for objects created and destroyed in current scope (do not return them at least).
Why does the StreamWriter need to remain open if I've flushed its
contents to the MemoryStream object already?
As #mikez mentioned, by default created StreamWriter "owns" the underlying stream, but you can avoid this behaviour by adding leaveOpen = true in constructor.
new StreamWriter(stream = s, encoding = Encoding.UTF8, bufferSize = 128, leaveOpen = true)
The other answers indicate I should use the constructor that has a leaveOpen param and set it to true, but I dislike this because the constructor also requires a bufferSize argument.
However, I realized that I can get away with this just as easily:
// new method body, returns byte array
var stream = new MemoryStream();
using (var writer = new StreamWriter(stream))
{
writer.WriteLine(string.Join(",", columnNames));
foreach (var user in users)
{
var row = leaderboard.Metrics.Select(m => Faker.RandomNumber.Next().ToString()).ToList();
row.Insert(0, user.UserName);
writer.WriteLine(string.Join(",", row));
}
writer.Flush();
stream.Position = 0;
}
return stream.ToArray();
// consumer opens a new stream using the bytes
using (var stream = new MemoryStream(this.GetCSVStream(leaderboard, users)))
{
mockFile.Setup(f => f.InputStream).Returns(stream);
this.service.UpdateEntries(update.ID, mockFile.Object);
}

Disposing of an object that has 2 streams

The following code is generating a warning. The problem is that we need the pipe to both read and write. How can I safely dispose of the pipe?
warning : CA2202 : Microsoft.Usage : Object 'pipe' can be disposed more than once in method 'ClientConnection.qaz()'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.: Lines: 465
void qaz()
{
const string THIS_SERVER = ".";
using (NamedPipeClientStream pipe = new NamedPipeClientStream(THIS_SERVER, this.Name,
PipeDirection.InOut,
PipeOptions.None))
{
using (StreamReader sr = new StreamReader(pipe))
{
string message = sr.ReadLine();
using (StreamWriter sw = new StreamWriter(pipe))
{
sw.WriteLine("ACK received");
}
}
}
}
You need Visual Studio Code Analysis to see these warnings (these are not c# compiler warnings).
The problem is that the StreamReader sr and the StreamWriter sw both Dispose of the object pipe.
You should iMHO ignore the warning and flag it. StreamReader is imho not supposed to dispose the inner stream. It does not own it.
What you are doing should 'safely' dispose of the pipe. I generally find this compiler warning highly irksome, objects should be happy to be disposed multiple times and indeed it is fine to do so for an instance of NamedPipeClientStream. I would suggest ignoring this warning here.
For information - the way to overcome this warning is to write your own try, finally blocks rather than using the using construct:
NamedPipeClientStream pipe = null;
try
{
pipe = new NamedPipeClientStream(THIS_SERVER, this.Name, PipeDirection.InOut, PipeOptions.None);
using (StreamReader sr = new StreamReader(pipe))
{
string message = sr.ReadLine();
using (StreamWriter sw = new StreamWriter(pipe))
{
sw.WriteLine("ACK received");
}
}
pipe = null;
}
finally
{
if (pipe != null)
{
pipe.Dispose();
}
}
Check out this example on MSDN on how to handle this case:
http://msdn.microsoft.com/en-us/library/ms182334.aspx
It is your pipe that is being disposed of twice, and I don't think this has anything to do with the fact that you're using both StreamReader and StreamWriter. Or perhaps it does, and you can just extend on the example similarly.

"Object can be disposed of more than once" error

When I run code analysis on the following chunk of code I get this message:
Object 'stream' can be disposed more than once in method 'upload.Page_Load(object, EventArgs)'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.
using(var stream = File.Open(newFilename, FileMode.CreateNew))
using(var reader = new BinaryReader(file.InputStream))
using(var writer = new BinaryWriter(stream))
{
var chunk = new byte[ChunkSize];
Int32 count;
while((count = reader.Read(chunk, 0, ChunkSize)) > 0)
{
writer.Write(chunk, 0, count);
}
}
I don't understand why it might be called twice, and how to fix it to eliminate the error. Any help?
I struggled with this problem and found the example here to be very helpful. I'll post the code for a quick view:
using (Stream stream = new FileStream("file.txt", FileMode.OpenOrCreate))
{
using (StreamWriter writer = new StreamWriter(stream))
{
// Use the writer object...
}
}
Replace the outer using statement with a try/finally making sure to BOTH null the stream after using it in StreamWriter AND check to make sure it is not null in the finally before disposing.
Stream stream = null;
try
{
stream = new FileStream("file.txt", FileMode.OpenOrCreate);
using (StreamWriter writer = new StreamWriter(stream))
{
stream = null;
// Use the writer object...
}
}
finally
{
if(stream != null)
stream.Dispose();
}
Doing this cleared up my errors.
To illustrate, let's edit your code
using(var stream = File.Open(newFilename, FileMode.CreateNew))
{
using(var reader = new BinaryReader(file.InputStream))
{
using(var writer = new BinaryWriter(stream))
{
var chunk = new byte[ChunkSize];
Int32 count;
while((count = reader.Read(chunk, 0, ChunkSize)) > 0)
{
writer.Write(chunk, 0, count);
}
} // here we dispose of writer, which disposes of stream
} // here we dispose of reader
} // here we dispose a stream, which was already disposed of by writer
To avoid this, just create the writer directly
using(var reader = new BinaryReader(file.InputStream))
{
using(var writer = new BinaryWriter( File.Open(newFilename, FileMode.CreateNew)))
{
var chunk = new byte[ChunkSize];
Int32 count;
while((count = reader.Read(chunk, 0, ChunkSize)) > 0)
{
writer.Write(chunk, 0, count);
}
} // here we dispose of writer, which disposes of its inner stream
} // here we dispose of reader
edit: to take into account what Eric Lippert is saying, there could indeed be a moment when the stream is only released by the finalizer if BinaryWriter throws an exception. According to the BinaryWriter code, that could occur in three cases
If (output Is Nothing) Then
Throw New ArgumentNullException("output")
End If
If (encoding Is Nothing) Then
Throw New ArgumentNullException("encoding")
End If
If Not output.CanWrite Then
Throw New ArgumentException(Environment.GetResourceString("Argument_StreamNotWritable"))
End If
if you didn't specify an output, ie if stream is null. That shouldn't be a problem since a null stream means no resources to dispose of :)
if you didn't specify an encoding. since we don't use the constructor form where the encoding is specified, there should be no problem here either (i didn't look into the encoding contructor too much, but an invalid codepage can throw)
if you don't pass a writable stream. That should be caught quite quickly during development...
Anyway, good point, hence the edit :)
The BinaryReader/BinaryWriter will dispose the underlying stream for you when it disposes. You don't need to do it explicitly.
To fix it you can remove the using around the Stream itself.
A proper implementation of Dispose is explicitly required not to care if it's been called more than once on the same object. While multiple calls to Dispose are sometimes indicative of logic problems or code which could be better written, the only way I would improve the original posted code would be to convince Microsoft to add an option to BinaryReader and BinaryWriter instructing them not to dispose their passed-in stream (and then use that option). Otherwise, the code required to ensure the file gets closed even if the reader or writer throws in its constructor would be sufficiently ugly that simply letting the file get disposed more than once would seem cleaner.
Your writer will dispose your stream, always.
Suppress CA2202 whenever you are sure that the object in question handles multiple Dispose calls correctly and that your control flow is impeccably readable. BCL objects generally implement Dispose correctly. Streams are famous for that.
But don't necessarily trust third party or your own streams if you don't have unit tests probing that scenario yet. An API which returns a Stream may be returning a fragile subclass.

Categories

Resources