TcpClient.GetStream()

Its best practice, you remember, to dispose of anything that implements IDisposable when you’re done with it.  The existence of the interface is a signal to the programmer that the garbage collector won’t clean this up after you.  If you don’t dispose of it, you’ll introduce a memory leak.

It’s only natural, then, when using TcpClient.GetStream, to want to dispose of the stream when you’re done with it.  However, this will close the connection, so, if you break your logic into a Read function and a Write function, you won’t have a good time.

This code doesn’t work:

private TcpClient client = new TcpClient();
public async Task<string> ConnectSendReceive(string message, int port)
{
Connect(port);
await Write(message);
return await Read();
}
private void Connect(int port)
{
client.Connect(new IPEndPoint(IPAddress.Loopback, port));
}
private async Task<string> Read()
{
using (var stream = client.GetStream())
{
byte[] receiveBuffer = new byte[2048];
int length = await stream.ReadAsync(receiveBuffer, 0, receiveBuffer.Length);
return Encoding.Default.GetString(receiveBuffer, 0, length);
}
}
private async Task Write(string message)
{
using (var stream = client.GetStream())
{
byte[] byteMessage = Encoding.Default.GetBytes(message);
await stream.WriteAsync(byteMessage, 0, byteMessage.Length);
}
}
view raw Client.cs hosted with ❤ by GitHub

Because the using will destroy the underlying network stream, closing the connection.  When you get to the Read(), an exception will be thrown because the connection is already closed.

Remember – you still want to close the socket when you’re finished!  The garbage collector won’t close the socket (because its unmanaged), so you do have to be conscious of this.  The easiest way is to just call Close() on the TcpClient.

This code does work:

private TcpClient client = new TcpClient();
public async Task<string> ConnectSendReceive(string message, int port)
{
Connect(port);
await Write(message);
string response = await Read();
client.Close();
return response;
}
private void Connect(int port)
{
client.Connect(new IPEndPoint(IPAddress.Loopback, port));
}
private async Task<string> Read()
{
var stream = client.GetStream();
byte[] receiveBuffer = new byte[2048];
int length = await stream.ReadAsync(receiveBuffer, 0, receiveBuffer.Length);
return Encoding.Default.GetString(receiveBuffer, 0, length);
}
private async Task Write(string message)
{
var stream = client.GetStream();
byte[] byteMessage = Encoding.Default.GetBytes(message);
await stream.WriteAsync(byteMessage, 0, byteMessage.Length);
}
view raw Client.cs hosted with ❤ by GitHub

Leave a Reply

Your email address will not be published. Required fields are marked *