I use NetworkStream with sockets in an SslStream socket server as follows:
stream = new NetworkStream(socket, true);
sslStream = new SslStream(stream, false);
My question is, if when I call sslStream.Dispose(), will the SslStream dispose/close its inner stream and its socket too?
Or do I need to explicitly close all three resources with sslStream.Close(), stream.Close() and socket.Close()?
If possible, you should use C#'s using construct to dispose the stream 'automatically' after use:
using (var sslStream = new SslStream(stream, false))
{
// read from stream here...
}
However, if you want to keep the SslStream for later use, you will have to dispose manually.
Disposing a stream typically closes the stream as well, the Close() method seems to be there mostly for completeness. You can download the .NET source code (or use a decompiler), and examine the SslStream.cs and its base class AuthenticatedStream.cs to see the exact behaviour.
To answer the rest of your question - The SslStream is well documented on Microsoft's MSDN site which shows one of SslStream's constructors takes two parameters (also shown by your example). The first parameter is the inner stream - which in your example the NetworkStream object. The second is a boolean called leaveInnerStreamOpen. In your example, you pass false.
It is this second value that determines the behaviour you are asking about: If you pass true, the inner stream will remain open when you close/dipose the SslStream (the stream will also be flushed). If you pass false, then the inner stream will be closed too.
Similarly for the NetworkStream, its constructor also takes a boolean ownsSocket. If this is set to true (as in your example), then disposing/closing the NetworkStream will also close its socket, otherwise it stays open.
Therefore, as your example code stands, you must call both sslStream.Dispose() and stream.Dispose() (the socket is closed automatically).
However, if you change the second parameter in the SslStream's constructor to true in your example code, you can just call sslStream.Dispose() to close the SslStream, the NetworkStream, and its socket.
Related
I was wondering if there is any method or property that allow us to see if there are available bytes to read in the stream associated to a BinaryReader (in my case, it is a NetworkStream, since I am performing a TCP communication).
I have checked the documentation and the only method I have seen is PeekChar(), but it only checks if there is a next byte (character), so in case there are many bytes to read, making a while loop to increase a counter may be inneficient.
Regarding the TCP communication, the problem is that the application protocol behind the TCP was not defined by me, and I am just trying to figure out how it works! Of course there will be some "length field" that will give me some clues about the bytes to read, but right know I am just checking how it works and this question came to my mind.
The BinaryReader itself doesn't have a DataAvailable property, but the NetworkStream does.
NetworkStream stream = new NetworkStream(socket);
BinaryReader reader = new BinaryReader(stream);
while (true)
{
if (stream.DataAvailable)
{
// call reader.ReadBytes(...) like you normally would!
}
// do other stuff here!
Thread.Sleep(100);
}
If you don't have a handle to the original NetworkStream at the point where you would call reader.ReadBytes(), you can use the BaseStream property.
while (true)
{
NetworkStream stream = reader.BaseStream as NetworkStream;
if (stream.DataAvailable)
{
// call reader.ReadBytes(...) like you normally would!
}
// do other stuff here!
Thread.Sleep(100);
}
BinaryReader will block until it reads all bytes required. The only exception is if it detects end of stream. But NetworkStream is an open stream and does not have the end of stream condition. So you can either create class with basic readers (ReadInt, ReadDouble, etc) that uses peek, reads byte by byte and does not block; or use another async technology.
I serve various TCP clients asynchronously via their respective TCP sockets. Currently, I have 3 tasks running simultaneously:
Await data from the NetworkStream using await StreamReader.ReadAsync()
Write data into the NetworkStream using await StreamWriter.WriteAsync()
Send watchdog messages periodically
Now, when I call something like this:
var stream = new NetworkStream(_socket);
// reading task
using (var reader = new StreamReader(stream)) {
// ...read...
}
The underlying NetworkStream gets eventually destroyed after reading has been done because StreamReader closes it on Dispose().
The easiest way would be not closing the StreamReader, but AFAIK this is a very bad idea. So, how can I handle asynchronous reading and writing while keeping the socket connection open?
From .NET 4.5 onwards, if you look through the constructor overloads for StreamReader and StreamWriter, there is one (and currently only one) constructor that takes a bool leaveOpen parameter. Use this overload and pass true - then it won't feel ownership of the underlying stream.
If this isn't available on your framework version, you'll have to create a NonClosingStream : Stream that decorates a stream using pass-thru implementations for everything except Close() and Dispose(), which should be no-ops (well, they could assign null to the field that represents the wrapped stream, but nothing more).
Since the StreamReader will always dispose the underling stream on its own disposal (that's why actually it is IDisposable), you do indeed have to not close it until you have no need in the network stream anymore.
So, this is very ok for the situation:
var stream = new NetworkStream(_socket);
var reader = new StreamReader(stream);
And when you are finish, you would close both of them, right?
reader.Dispose();
stream.Dispose();
I'm reading the documentation on TcpClient.Close() and noticed this:
Calling this method will eventually result in the close of the associated Socket and will also close the associated NetworkStream that is used to send and receive data if one was created.
So, correct me if I'm wrong but this says that if one calls Close() on the TcpClient that the NetworkStream will also be closed.
So then why at the end of the code example are both Close() called?
networkStream.Close();
tcpClient.Close();
Would it be just as fine to only call tcpClient.Close();?
Responding to this question since no one else did so that I may accept an answer.
According to Hans, calling NetworkStream.Close() is unnecessary because TcpClient.Close() closes its underlying NetworkStream.
NetworkStream and TcpClient implement IDisposable. So best practise in my opinion is to pack it into a using block, so you never need to close or dispose it manually.
Closing the client does not close the stream, it's in the doc of the GetStream method.
For the reference, have a look to this discussion : How to properly and completely close/reset a TcpClient connection?
You should Just do "TcpClient.Close()"
Or if you must, type both
I have been sending binary data between applications lots of times over TCP sockets but never before using strings. Bumbed into an issue intending to do so. Here is what I got:
TcpClient tcpClient = new TcpClient("localhost", port);
//Connects fine
NetworkStream ns = tcpClient.GetStream();
StreamWriter sw = new StreamWriter(ns);
//The code moves on but nothing seems to be sent unless I do
//a sw.Close() after this line. That would however close the
//ns and prevent me from reading the response further down
sw.Write("hello");
//I am using a stream reader with ReadToEnd() on the tcpListener
//which never receives the string from this piece of code
//Since the above never actually send I get stuck here
string response = new StreamReader(ns).ReadToEnd();
sw.Close();
tcpClient.Close();
How do I send the string without closing the network stream? ns.Flush() is what I would be looking for really.
You have an sw.Flush() , that ought to work. A WriteLine() might have done it too.
But when the other side does a ReadLine() then you have to make sure you end with newline. Try WriteLine() instead of Write().
And be careful about closing a StreamReader/Writer, they also close their underlying streams.
There's a StreamWriter.Flush(). When you get done with sending you message, just do sw.Flush(). However, since buffer sizes are fairly large (upto a couple KB), the correct way is to only Flush() just before you wait for a response. That way several calls to .Write() can be bundled into a single packet and sent down the wire at the same time.
You just need to set the AutoFlush property on the StreamWriter to true.
I have a class that essentially wraps a Stream for reading/writing, but that stream is expected to be managed by the consumer of that class. For ease of use, I use StreamReader and StreamWriter classes to perform I/O operations on the stream. Normally I'd wrap the reader and writer in using blocks, but I want to avoid closing the reader and writer because doing so also closes the underlying stream and I have to keep it open.
Is it safe in terms of memory/resource management to not close a StreamReader/StreamWriter if I expect the underlying Stream to be managed by the caller? Will the reader and writer be garbage collected when the stream is explicitly closed elsewhere?
public class Wrapper
{
private Stream _underlyingStream;
public Wrapper(Stream underlyingStream)
{
_underlyingStream = underlyingStream;
}
public string GetValue()
{
_underlyingStream.Seek(0, SeekOrigin.Begin);
var reader = new StreamReader(_underlyingStream);
return reader.ReadToEnd(); // we're done, but the stream is not ours to close
}
}
If nobody closes the streams then ultimately the finalizer will be called which should call dispose and close them upon GC. But that's quite a crap-shoot resource-wise because it leaves whatever possibly-expensive resources allocated until GC. It could get worse the longer your object lives, especially if it survives collections to be promoted to gen 1 or even 2.
It sure would be nice if you could present something to your caller that isolates this. Perhaps you can cache something from the stream so you can close it while still serving the content to your caller?
EDIT after your edit: Now that I see your caller PASSES you a stream to operate on, my answer has to be different! It's very clear that your caller should be managing the stream's lifetime. I had the impression at first that your class created a stream and hoped the caller managed it.
The easiest way to solve this is to wrap the stream in your own class that derives from System.IO.Stream
Example:
http://csharptest.net/browse/src/Library/IO/NonClosingStream.cs
It is definetelly not ok.
read this from msdn
The close calls the Dispose method passing a true value.
Flushing the stream will not flush its underlying encoder unless you explicitly call Close.
Try to encapsulate all IO in a class.