TCP network stream handling - c#

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();

Related

protobuf.net De-Serializer waits indefinitely

I have got a simple TCPlistener that listens for connections and once a connection has been established, a method tries to send data and the server side tries to read it.
client side:
using (NetworkStream stream = new NetworkStream(_client.Client, false))
{
Serializer.Serialize(stream, MyPersonObject);
}
Server side:
using (NetworkStream stream = new NetworkStream(_client.Client, false))
{
var myObject = Serializer.DeSerialize<Person>(stream);
}
However, I've noticed that once it hits the DeSerialize method, it hangs and waits indefinitely.
Note that this does NOT happen with BinaryFormatter using the exact same steps. I am not sure what's wrong.
A protobuf stream is not "closed" - it reads until the end of the stream by default, which means it will read until the inbound TCP socket is mark as complete.
If you intend to send multiple messages, try using the "WithLengthPrefix" versions of serialize and deserialize; that adds message framing for you, allowing it to know where each payload ends.

Does SslStream.Dispose dispose its inner stream

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.

Reusing a stream after a method has completed

I am currently working on a C# project that uses a FileStream to open a file and passes the information to a StreamReader for it to be processed.
What I want to be able to do is I have a method which passes the stream to another method, that does the processing and once that method finishes, the original method calls another method passing it the same stream. However, when the first stream process completes when the second method is called it displays an exception saying that the thread is not readable.
When I look at debugging the stream, when I look at the details about the stream it says that it cannot be read, seek or write, and the length parameter of the stream says threw an exception of type System.ObjectDisposedException.
The question is, how can I keep the stream readable after the first method has completed so that the same stream can be processed in the second stream.
Thanks for any help you can provide.
if your streamReader is part of "using" statement, it disposes the file stream in the end of the statement block.
using (StreamReader reader = new StreamReader(fileStream))
{
..
}
Simple solution is not to dispose the reader explicitly, leaving it to GC
[More thoughts]
If most of the methods are accessing file stream through TextReader interface, you can pass reader thus avoiding the problem with the ownership.
If I understood you correctly, your stream is getting closed too fast. Based on what you say, it might be because you are Closing or Disposing StreamReader which, according to documentation, will close underlying stream.
Try not closing StreamReader (just ignore it, after it's not needed).
For example, if your code looks like this:
void P()
{
var stream = new FileStream();
P1(stream);
P2(stream);
}
void P1(FileStream stream)
{
using (var reader = new StreamReader(stream))
{
......
} //Here you would have disposed StreamReader and close FileStream
}
void P2(FileStream stream) // Stream is already closed
{
}
You have closed your stream in 1st method. You will have the same problem if you call:
reader.Dispose();
reader.Close();
stream.Dispose();
stream.Close();
using (stream);
So make sure aren't doing any of those things.
Btw: in C#5 I have heard, that Readers/Writers will be parametrized, if you want then to close underlying stream when they are closed (just like CryptoStream have right now)

read/write string over tcp network stream

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.

Is it okay to not close StreamReader/StreamWriter to keep the underlying stream open?

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.

Categories

Resources