Note: If you want to experience a complete C++ .NET/C++-CLI programming tutorial please jump to Visual C++ .NET programming tutorial.
Composable stream classes are streams that can perform I/O on top of another underlying stream. It’s important to understand that the underlying stream can be a base stream or even another composable stream. As we mentioned earlier, composable streams have constructors that accept a stream as a parameter. This is a powerful idea because you can layer I/O techniques for reading data from and writing data to resources. For example, if you want to encrypt some data and save it to a file, you could simply open a base stream-FileStream-followed by a composable stream, CryptoStream and then begin writing encrypted data to a file, as shown in Figure 2-4. In the .NET Framework version 1, only two composable streams are available: BufferedStream and CryptoStream.
Figure 2-4: Layering one stream on top of another stream
Take note that in the .NET Framework version 2, there is a composable stream to handle Secure Sockets Layer (SSL) communications over a stream. This new stream will allow you to use streams to communicate to an SSL server over a network by layering an SSL-composable stream over a network stream.
BufferedStream is an interesting class that’s designed to improve I/O performance when either reading or writing to another stream. This composable stream can be very useful, especially if your application performs I/O by reading or writing data in very small amounts. The class maintains an internal buffer to cache or collect the data, and at some point it will automatically flush data to the next stream or hold data until your application is ready to read from the stream.
By default, the BufferedStream class maintains a buffer of 4096 bytes. You can override the default by specifying any size buffer through the constructor, depending on your application’s needs. The buffer can be used only for read or write operations, but not for both at the same time. If your application alternates between Read() and Write() calls continuously, the buffer will not be used very effectively. So, if you’re developing an application that makes a series of either Read() or Write() calls using small amounts of data, the BufferedStream class can potentially improve I/O performance with operating system resources.
Create a new CLR console application project and you might want to use BufferedStreamSampleCP as the project and solution names.
Add the following code.
// BufferedStreamSampleCP.cpp : main project file. // <summary> // This sample demonstrates how to use the BufferedStream class to // improve IO performance on a network stream. This sample is a // revision of the network stream Sender sample that includes the // composable stream BufferedStream. // // sample has 2 optional parameters that can be used: // Sender [/server <server IP>] [/port <port>] // By default this application will connect to the server on the same machine using TCP port 5150. // </summary>
#include "stdafx.h"
using namespace System; using namespace System::IO; using namespace System::Net; using namespace System::Net::Sockets;
// <summary> // The main entry point for the application. // </summary> [STAThread] int main(array<System::String ^> ^args) { // The following are the default values String^ ServerName = "127.0.0.1"; int Port = 5150;
args = Environment::GetCommandLineArgs();
if(args->Length != 1) { // Parse command line arguments if any for (int i = 0; i < args->Length; i++) { if (String::Compare(args[i], "/server", true) == 0) { // The server's name we will connect to ServerName = args[++i]->ToString(); } else if (String::Compare(args[i], "/port", true) == 0) { // The port on which the server is listening Port = System::Convert::ToInt32(args[++i]->ToString()); } } } else { Console::WriteLine("Usage: {0} [/server <server IP>] [/port <port>]", args[0]); return 0; }
Socket^ ClientSocket = nullptr;
try { // Let's connect to a listening server Console::WriteLine("Connecting to listening server..."); try { ClientSocket = gcnew Socket(AddressFamily::InterNetwork, SocketType::Stream, ProtocolType::IP); Console::WriteLine("Socket() is OK..."); } catch (Exception^ e) { throw gcnew Exception("Failed to create client Socket: " + e->Message); } IPEndPoint^ ServerEndPoint = gcnew IPEndPoint(IPAddress::Parse(ServerName), Convert::ToInt16(Port)); try { ClientSocket->Connect(ServerEndPoint); Console::WriteLine("Connect() is OK..."); } catch (Exception^ e) { throw gcnew Exception("Failed to connect client Socket: " + e->Message); } } catch (Exception^ e) { Console::WriteLine(e->Message); Console::WriteLine("Closing Socket..."); ClientSocket->Close(); return 0; } // Let's create a network stream to communicate over the connected Socket. NetworkStream^ ClientNetworkStream = nullptr;
try { try { // Setup a network stream on the client Socket Console::WriteLine("Instantiate NetworkStream object..."); ClientNetworkStream = gcnew NetworkStream(ClientSocket, true); } catch (Exception^ e) { // We have to close the client socket here because the network stream did not take ownership of the socket. throw gcnew Exception("Failed to create a NetworkStream with error: " + e->Message); Console::WriteLine("Closing client Socket..."); ClientSocket->Close(); } } catch (Exception^ e) { Console::WriteLine(e->Message); Console::WriteLine("Closing client NetworkStream..."); ClientNetworkStream->Close(); return 0; }
BufferedStream^ ClientBufferedStream = nullptr;
try { try { // Setup a network stream on the client Socket Console::WriteLine("Instantiate BufferedStream object..."); ClientBufferedStream = gcnew BufferedStream(ClientNetworkStream); } catch (Exception^ e) { throw gcnew Exception("Failed to create a BufferedStream with error: " + e->Message); }
try { Console::WriteLine("Writing/sending data..."); array< Byte >^ Buffer = gcnew array< Byte >(1);
for (int i = 0; i < 200; i++) { Buffer[0] = (Byte)i; ClientBufferedStream->Write(Buffer, 0, Buffer->Length); } Console::WriteLine("We wrote 200 bytes one byte at a time to the server."); } catch (Exception^ e) { throw gcnew Exception("Failed to write to client BufferedStream with error: " + e->Message); } } catch (Exception^ e) { Console::WriteLine(e->Message); } finally { // We are finished with the Stream so we will close it. Console::WriteLine("Closing the BufferedStream..."); ClientBufferedStream->Close(); } return 0; } |
Build and run the project. The following is output example.
Let test this program against receiver program. In this case we use the NetworkStreamSampleCPReceiver program. Firstly, run the receiver program.
Then run the BufferedStreamSampleCP program.
The following is the screenshot for the received data when the communication was completed.
|
![]() |
Create a new console application project. You can use the solution and project name as shown in the following Figure.
Add the following code.
using System; using System.IO; using System.Net; using System.Net.Sockets; using System.Collections.Generic; using System.Linq; using System.Text;
// <summary> // This sample demonstrates how to use the BufferedStream class to // improve IO performance on a network stream. This sample is a // revision of the network stream Sender sample that includes the composable stream BufferedStream. // // sample has 2 optional parameters that can be used: // Sender [/server <server IP>] [/port <port>] // By default this application will connect to the server on the same machine using TCP port 5150. // </summary> namespace BufferedStreamSampleCS { class Program { // <summary> // The main entry point for the application. // </summary> [STAThread] static void Main(string[] args) { // The following is the default values string ServerName = "127.0.0.1"; int Port = 5150;
// Parse command line arguments if any for (int i = 0; i < args.Length; i++) { try { if (String.Compare(args[i], "/server", true) == 0) { // The server's name we will connect to ServerName = args[++i].ToString(); } else if (String.Compare(args[i], "/port", true) == 0) { // The port on which the server is listening Port = System.Convert.ToInt32(args[++i].ToString()); } } catch (System.IndexOutOfRangeException) { Console.WriteLine("Usage: Executable_file_name [/server <server IP>] [/port <port>]"); return; } }
Socket ClientSocket = null;
try { // Let's connect to a listening server try { ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); Console.WriteLine("Socket() is OK..."); } catch (Exception e) { throw new Exception("Failed to create client Socket: " + e.Message); } IPEndPoint ServerEndPoint = new IPEndPoint(IPAddress.Parse(ServerName), Convert.ToInt16(Port)); try { ClientSocket.Connect(ServerEndPoint); Console.WriteLine("Connect() is OK..."); } catch (Exception e) { throw new Exception("Failed to connect client Socket: " + e.Message); } } catch (Exception e) { Console.WriteLine(e.Message); ClientSocket.Close(); return; }
// Let's create a network stream to communicate over the connected Socket. NetworkStream ClientNetworkStream = null; try { try { // Setup a network stream on the client Socket Console.WriteLine("Instantiate NetworkStream object..."); ClientNetworkStream = new NetworkStream(ClientSocket, true); } catch (Exception e) { // We have to close the client socket here because the network stream did not take ownership of the socket. ClientSocket.Close(); throw new Exception("Failed to create a NetworkStream with error: " + e.Message); } } catch (Exception e) { Console.WriteLine(e.Message); ClientNetworkStream.Close(); return; }
BufferedStream ClientBufferedStream = null;
try { try { // Setup a network stream on the client Socket Console.WriteLine("Instantiate BufferedStream object..."); ClientBufferedStream = new BufferedStream(ClientNetworkStream); } catch (Exception e) { throw new Exception("Failed to create a BufferedStream with error: " + e.Message); }
try { Console.WriteLine("Writing/sending data..."); byte[] Buffer = new byte[1]; for (int i = 0; i < 200; i++) { Buffer[0] = (byte)i; ClientBufferedStream.Write(Buffer, 0, Buffer.Length); } Console.WriteLine("We wrote 200 bytes one byte at a time to the server."); } catch (Exception e) { throw new Exception("Failed to write to client BufferedStream with error: " + e.Message); } } catch (Exception e) { Console.WriteLine(e.Message); } finally { // We are finished with the Stream so we will close it. ClientBufferedStream.Close(); } } } } |
An output sample:
By using the previous receiver program, we have the following sample output. Firstly run the receiver program and then run the sender program.
Create a new console application project. You can use the solution and project name as shown in the following Figure.
Add the following code.
Imports System Imports System.IO Imports System.Net Imports System.Net.Sockets
'This sample demonstrates how to use the BufferedStream class to ' improve IO performance on a network stream. This sample is a ' revision of the network stream Sender sample that includes the composable stream BufferedStream. ' ' This sample has 2 optional parameters that can be used: ' Sender [/server <server IP>] [/port <port>] ' By default this application will connect to the server on the same machine using TCP port 5150. Module Module1 'The main entry point for the application. Sub Main() ' The following is the default values Dim ServerName As String = "127.0.0.1" Dim Port As Integer = 5150
' Parse command line arguments if any Dim args As String() = Environment.GetCommandLineArgs() Dim i As Integer
For i = 1 To args.Length - 1 Try If args(i) = "/server" Then ' The server's name we will connect to i = i + 1 ServerName = args(i).ToString() ElseIf args(i) = "/port" Then ' The port on which the server is listening i = i + 1 Port = System.Convert.ToInt32(args(i).ToString()) End If Catch e As System.IndexOutOfRangeException Console.WriteLine("Usage: Sender [/server <server IP>] [/port <port>]") Exit Sub End Try Next
Dim ClientSocket As Socket = Nothing
Try ' Let's connect to a listening server Try ClientSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP) Console.WriteLine("Socket() is OK...") Catch e As Exception Throw New Exception("Failed to create client Socket: " + e.Message) End Try
Dim ServerEndPoint As IPEndPoint = New IPEndPoint(IPAddress.Parse(ServerName), Convert.ToInt16(Port))
Try ClientSocket.Connect(ServerEndPoint) Console.WriteLine("Connect() is OK...") Catch e As Exception Throw New Exception("Failed to connect client Socket: " + e.Message) End Try Catch e As Exception Console.WriteLine(e.Message) ClientSocket.Close() Exit Sub End Try
' Let's create a network stream to communicate over the connected Socket. Dim ClientNetworkStream As NetworkStream = Nothing
Try Try ' Setup a network stream on the client Socket ClientNetworkStream = New NetworkStream(ClientSocket, True) Console.WriteLine("Instantiate NetworkStream is OK...") Catch e As Exception ' We have to close the client socket here because the network stream did not take ownership of the socket. ClientSocket.Close() Throw New Exception("Failed to create a NetworkStream with error: " + e.Message) End Try Catch e As Exception Console.WriteLine(e.Message) ClientNetworkStream.Close() Exit Sub End Try
Dim ClientBufferedStream As BufferedStream = Nothing
Try Try ' Setup a network stream on the client Socket ClientBufferedStream = New BufferedStream(ClientNetworkStream) Console.WriteLine("Instantiate BufferedStream is OK...") Catch e As Exception Throw New Exception("Failed to create a BufferedStream with error: " + e.Message) End Try
Try Dim Buffer(1) As Byte
Console.WriteLine("Writing/sending some data...") For i = 1 To 200 Buffer(0) = i ClientBufferedStream.Write(Buffer, 0, Buffer.GetUpperBound(0)) Next Console.WriteLine("We wrote 200 bytes one byte at a time to the server.") Catch e As Exception Throw New Exception("Failed to write to client BufferedStream with error: " + e.Message) End Try Catch e As Exception Console.WriteLine(e.Message) Finally ' We are finished with the Stream so we will close it. ClientBufferedStream.Close() End Try End Sub End Module |
An output sample:
Running both the previous VB receiver program and this example giving the following output.