Note: If you want to experience a complete C++ .NET/C++-CLI programming tutorial please jump to Visual C++ .NET programming tutorial.
Create a new CLR console application project and you might want to use NegotiatedStreamClientCP as the project and solution names.
Add the following code.
// NegotiatedStreamClientCP.cpp : main project file.
#include "stdafx.h"
using namespace System; using namespace System::Net; using namespace System::Net::Security; using namespace System::Net::Sockets; using namespace System::Text;
// The following class displays the properties of an authenticatedStream. public ref class AuthenticatedStreamReporter { public: static void DisplayProperties( AuthenticatedStream^ stream ) { Console::WriteLine( L"IsAuthenticated: {0}", stream->IsAuthenticated ); Console::WriteLine( L"IsMutuallyAuthenticated: {0}", stream->IsMutuallyAuthenticated ); Console::WriteLine( L"IsEncrypted: {0}", stream->IsEncrypted ); Console::WriteLine( L"IsSigned: {0}", stream->IsSigned ); Console::WriteLine( L"IsServer: {0}", stream->IsServer ); } };
public ref class ASynchronousAuthenticatingTcpClient { private: static TcpClient^ client = nullptr;
public: void AnotherDayAnotherMain() { // Establish the remote endpoint for the socket. For this example, use the local machine. Console::WriteLine( L"Using localhost as remote endpoint..."); // IPHostEntry^ ipHostInfo = Dns::GetHostEntry( "localhost" ); // You may try other remote point such as valid domain names and IP addresses IPHostEntry^ ipHostInfo = Dns::GetHostEntry(Dns::GetHostName()); IPAddress^ ipAddress = ipHostInfo->AddressList[0];
try { // Client and server use port 1234. Console::WriteLine( L"Using {0} port 1234...", ipAddress); IPEndPoint^ remoteEP = gcnew IPEndPoint( ipAddress,1234 );
// Create a TCP/IP socket. Console::WriteLine( L"Creating a TCP/IP socket..."); // UdpClient and TcpClient create a IPv4 socket in the default constructor Then passing iPv6 will fail... // client = gcnew TcpClient; // So use this... client = gcnew TcpClient(ipAddress->AddressFamily);
// Connect the socket to the remote endpoint. Console::WriteLine( L"Connecting the socket to the remote endpoint..."); client->Connect( remoteEP ); Console::WriteLine( L"Client connected to {0}.", remoteEP->ToString() );
// Ensure the client does not close when there is still data to be sent to the server. Console::WriteLine( L"Don't close if there is data..."); client->LingerState = (gcnew LingerOption( true,0 ));
// Request authentication. Console::WriteLine( L"Requesting authentication..."); NetworkStream^ clientStream = client->GetStream(); NegotiateStream^ authStream = gcnew NegotiateStream( clientStream,false );
// Pass the NegotiateStream as the AsyncState object so that it is available to the callback delegate. Console::WriteLine( L"Passing the NegotiateStream as the AsyncState object..."); IAsyncResult^ ar = authStream->BeginAuthenticateAsClient( gcnew AsyncCallback( EndAuthenticateCallback ), authStream );
Console::WriteLine( L"Client waiting for authentication..." );
// Wait until the result is available. Console::WriteLine( L"Waiting until the result is available..."); ar->AsyncWaitHandle->WaitOne();
// Display the properties of the authenticated stream. Console::WriteLine( L"Displaying the properties of the authenticated stream..."); AuthenticatedStreamReporter::DisplayProperties( authStream );
// Send a message to the server. Encode the test data into a byte array. array<Byte>^message = Encoding::UTF8->GetBytes( L"Client: Hello buddy..." ); ar = authStream->BeginWrite(message, 0, message->Length, gcnew AsyncCallback( EndWriteCallback ), authStream ); ar->AsyncWaitHandle->WaitOne(); Console::WriteLine( L"Sent {0} bytes.", message->Length );
// Close the client connection. Console::WriteLine( L"Closing the client connection..."); authStream->Close(); Console::WriteLine( L"Client closed..." ); } catch(Exception^ err) { Console::WriteLine("Got some errors:\n " + err->Message); Console::WriteLine("You may need to run the server first..."); } }
// The following method is called when the authentication completes. static void EndAuthenticateCallback( IAsyncResult^ ar ) { Console::WriteLine( L"Client ending authentication..." ); NegotiateStream^ authStream = dynamic_cast<NegotiateStream^>(ar->AsyncState); // End the asynchronous operation. authStream->EndAuthenticateAsClient( ar ); // Console.WriteLine("AllowedImpersonation: {0}", authStream.AllowedImpersonation); }
// The following method is called when the write operation completes. static void EndWriteCallback( IAsyncResult^ ar ) { Console::WriteLine( L"Client ending write operation..." ); NegotiateStream^ authStream = dynamic_cast<NegotiateStream^>(ar->AsyncState); // End the asynchronous operation. authStream->EndWrite( ar ); } };
int main(array<System::String ^> ^args) { ASynchronousAuthenticatingTcpClient^ aatc = gcnew ASynchronousAuthenticatingTcpClient; aatc->AnotherDayAnotherMain(); return 0; } |
Build and run the project.
The following are output examples when running both the server and client program on localhost. Unblock the Windows security alert if any.
![]() |
|
Firstly, we run the server and start listening for connection.
Then, we run the client on another Windows console.
The following screenshot shows the server program after the communication completed.
The following code example demonstrates the client side (NegotiateStreamClientCS) of a client-server connection that uses the NegotiateStream. The client authenticates and sends a message to the server asynchronously. Create a new console application project. You can use the solution and project name as NegotiateStreamClientCS.
using System; using System.Collections.Generic; using System.Net; using System.Net.Security; using System.Net.Sockets; using System.Text;
namespace NegotiateStreamClient { public class ASynchronousAuthenticatingTcpClient { static TcpClient client = null;
public static void Main(String[] args) { // Establish the remote endpoint for the socket. For this example, use the local machine. IPHostEntry ipHostInfo = Dns.GetHostEntry("localhost"); IPAddress ipAddress = ipHostInfo.AddressList[0]; // Client and server use port 11000. IPEndPoint remoteEP = new IPEndPoint(ipAddress, 11000); // Create a TCP/IP socket. client = new TcpClient(); // Connect the socket to the remote endpoint. client.Connect(remoteEP); Console.WriteLine("Client connected to {0}.", remoteEP.ToString()); // Ensure the client does not close when there is still data to be sent to the server. client.LingerState = (new LingerOption(true, 0)); // Request authentication. NetworkStream clientStream = client.GetStream(); NegotiateStream authStream = new NegotiateStream(clientStream, false); // Pass the NegotiateStream as the AsyncState object so that it is available to the callback delegate. IAsyncResult ar = authStream.BeginAuthenticateAsClient(new AsyncCallback(EndAuthenticateCallback),authStream); Console.WriteLine("Client waiting for authentication..."); // Wait until the result is available. ar.AsyncWaitHandle.WaitOne(); // Display the properties of the authenticated stream. AuthenticatedStreamReporter.DisplayProperties(authStream); // Send a message to the server. Encode the test data into a byte array. byte[ ] message = Encoding.UTF8.GetBytes("Hello from the client."); ar = authStream.BeginWrite(message, 0, message.Length, new AsyncCallback(EndWriteCallback), authStream); ar.AsyncWaitHandle.WaitOne(); Console.WriteLine("Sent {0} bytes.", message.Length); // Close the client connection. authStream.Close(); Console.WriteLine("Client closed."); } // The following method is called when the authentication completes. public static void EndAuthenticateCallback(IAsyncResult ar) { Console.WriteLine("Client ending authentication..."); NegotiateStream authStream = (NegotiateStream)ar.AsyncState; // End the asynchronous operation. authStream.EndAuthenticateAsClient(ar); // Console.WriteLine("AllowedImpersonation: {0}", authStream.AllowedImpersonation); } // The following method is called when the write operation completes. public static void EndWriteCallback(IAsyncResult ar) { Console.WriteLine("Client ending write operation..."); NegotiateStream authStream = (NegotiateStream)ar.AsyncState; // End the asynchronous operation. authStream.EndWrite(ar); } }
// The following class displays the properties of an authenticatedStream. public class AuthenticatedStreamReporter { public static void DisplayProperties(AuthenticatedStream stream) { Console.WriteLine("IsAuthenticated: {0}", stream.IsAuthenticated); Console.WriteLine("IsMutuallyAuthenticated: {0}", stream.IsMutuallyAuthenticated); Console.WriteLine("IsEncrypted: {0}", stream.IsEncrypted); Console.WriteLine("IsSigned: {0}", stream.IsSigned); Console.WriteLine("IsServer: {0}", stream.IsServer); } } } |
An output sample:
Running both the client and server programs. Firstly, run the server program and then the client program. A sample output is shown below.
An output sample: