< VB .NET Binary SOAP Program Example | Main | C# Binary Socket Server Program Example >

 


 

Chapter 4 Part 5:

Serialization

 

 

What do we have in this chapter 4 Part 5?

  1. C++ Binary Socket Server Program Example

  2. Creating Shared C++ DLL Class

  3. C++ Binary Socket Client Program Example

 

 

C++ Binary Socket Server Program Example

 

In the following example, we create will create three solutions with three projects respectively (shared DLL, server and client program). The shared DLL will be used by both the server and the client programs.

 

Creating Shared C++ DLL Class

 

Firstly, let create the shared DLL. Create a CLR class library project. You can use BinDataCP as the solution and project names.

 

Creating Shared C++ DLL Class

 

Manually, change the class name to BinDataSubClass as shown in the following Figure. We can use the BinDataCP namespace, in our server and client program later to access the related methods defined in those classes.

 

Creating Shared C++ DLL Class - renaming the class name

 

Add the following code for the BinDataSubClass class.

 

// BinDataCP.h

 

#pragma once

 

using namespace System;

 

namespace BinDataCP {

 

            [Serializable]

            public ref class BinDataSubClass

            {

                        public:

                        int SubField1;

 

        /// <summary>

        /// Simple constructor for the class which initialized the properties

        /// </summary>

        public:

        BinDataSubClass()

        {

            SubField1 = -1;

        }

 

        /// <summary>

        /// Prints the class values to the console

        /// </summary>

        public:

        void Print()

        {

               Console::WriteLine("In BinDataSubClass...");

               Console::WriteLine("BinDataSubClass::SubField1 = {0}", SubField1);

        }

};

 

Next, add another class, BinDataClass.

 

    [Serializable]

    public ref class BinDataClass

    {

            public:

                        int Field1;

                        String^ Field2;

                        BinDataSubClass^ SubClass;

 

        /// <summary>

        /// Simple constructor that initializes the member properties.

        /// </summary>

        public:

        BinDataClass()

        {

            SubClass = gcnew BinDataSubClass();

            Field1 = 1234;

            Field2 = "Field2";

        }

 

        /// <summary>

        /// Prints the class members to the console

        /// </summary>

        public:

        void Print()

        {

            Console::WriteLine("In BinDataClass...");

            Console::WriteLine("BinDataClass::Field1 = {0}", Field1);

            Console::WriteLine("BinDataClass::Field2 = {0}", Field2);

            SubClass->Print();

        }

    };

}

 

Build this project and make sure there is no error. The generated DLL file should be expected as shown below under the project Debug’s folder. Close the project/solution when done.

 

Creating Shared C++ DLL Class - the generated DLL file ready for use

 

Next, we would like to create the server program. Create a new CLR console application project. You can use the solution and project name, SocketBinaryServerCP as shown in the following Figure.

 

C++ Binary Server Socket - Creating the server program

 

First of all, let add a reference to the classes (shared DLL) created previously. Select the project folder > Right click mouse > Select the References context menu.

 

C++ Binary Server Socket program example - adding reference to a DLL

 

Click the Add New Reference button.

 

C++ Binary Server Socket program example - adding reference to existing class

 

Browse the BinDataCP.DLL file generated in the previous project.

 

C++ Binary Server Socket program example - browsing and finding DLL file

 

Click the OK button after selecting the BinDataCP.dll file.

 

C++ Binary Server Socket program example - selecting the DLL file

 

You can see that the DLL file has been imported to the project folder.

 

C++ Binary Server Socket program example - the DLL file has been imported into project folder

 

Add the namespaces as shown below that include the BinDataCP.

 

C++ Binary Server Socket program example - adding the using namespaces

 

using namespace System::Net;

using namespace System::Net::Sockets;

using namespace System::Runtime::Serialization;

using namespace System::Runtime::Serialization::Formatters::Binary;

using namespace BinDataCP;

 

Build and run the project to make sure there is no error in the reference to the BinDataCP namespace.

 

Then, add the usage() function.

 

static void usage()

{

            Console::WriteLine("executable_file_name [/protocol IPv4|IPv6] [/port num]");

}

 

C++ Binary Server Socket program example - adding usage() function

 

Finally, complete the main() code.

 

int main(array<System::String ^> ^args)

{

    int Port = 5150;

    Socket^ ListeningSocket = nullptr;

    Socket^ ClientSocket = nullptr;

    IPEndPoint^ LocalEndPoint = nullptr;

    NetworkStream^ NetStream;

    IFormatter^ formatter = gcnew BinaryFormatter();

    BinDataClass^ data;

    array<Byte>^ buffer = gcnew array<Byte>(5);

    // Default is IPv4

    AddressFamily^ ServerAddressFamily = AddressFamily::InterNetwork;

 

            if(args->Length != 0)

            {

                        // Parse the command line

                        for (int i = 0; i < args->Length; i++)

                        {

                                    if (String::Compare(args[i], "/protocol", true) == 0)

                                    {

                                                try

                                                {

                                                            // Create the appropriate listening socket

                                                            Console::WriteLine("Creating the appropriate listening socket...");

                                                            i++;

                                                            if (String::Compare(args[i], "IPv6", true) == 0)

                                                            {

                                                                        ServerAddressFamily = AddressFamily::InterNetworkV6;

                                                                        ListeningSocket = gcnew Socket(

                                                                        AddressFamily::InterNetworkV6,

                                                                        SocketType::Stream,

                                                                        ProtocolType::Tcp

                                                                        );

                                                                        LocalEndPoint = gcnew IPEndPoint( IPAddress::IPv6Any, Port );

                                                                        Console::Write("IPv6 Socket() is OK. IP: {0}, ", IPAddress::IPv6Any);

                                                            }

                                                            else if (String::Compare(args[i], "IPv4", true) == 0)

                                                            {

                                                                        ServerAddressFamily = AddressFamily::InterNetwork;

                                                                        ListeningSocket = gcnew Socket(

                                                                        AddressFamily::InterNetwork,

                                                                        SocketType::Stream,

                                                                        ProtocolType::Tcp

                                                                        );

                                                                        LocalEndPoint = gcnew IPEndPoint(IPAddress::Any, Port);

                                                                        Console::Write("IPv4 Socket() is OK. IP: {0}, ", IPAddress::Any);

                                                            }

                                                            else

                                                            {

                                                                        usage();

                                                                        return 0;

                                                            }

                                                }

                                                catch (IndexOutOfRangeException^)

                                                {

                                                            usage();

                                                            return 0;

                                                }

                                    }

                                    else if (String::Compare(args[i], "/port", true) == 0)

                                    {

                                                try

                                                {

                                                            Port = Convert::ToInt32(args[++i]);

                                                }

                                                catch (IndexOutOfRangeException^)

                                                {

                                                            usage();

                                                            return 0;

                                                }

                                    }

                                    else

                                    {

                                                usage();

                                                return 0;

                                    }

                        }

            }

            else

            {

                        usage();

                        return 0;

            }

 

            Console::WriteLine("Port: " + Port);

            // Bind the socket to the interface we will accept connections one

            ListeningSocket->Bind(LocalEndPoint);

            Console::WriteLine("Bind() looks OK...");

 

            // Set the listen backlog to five

            ListeningSocket->Listen(5);

            Console::WriteLine("Listen() looks OK...");

            Console::WriteLine("I'm listening for connection buddy...");

 

    // Wait until a client connects

    ClientSocket = ListeningSocket->Accept();

    Console::WriteLine("Accept() looks OK...");

 

    // Create a NetworkStream for the accepted client connection

    NetStream = gcnew NetworkStream(ClientSocket);

    Console::WriteLine("Instantiating a NetworkStream...");

 

    // Read the string "hello" from the stream since this was send before the serialized object.

    NetStream->Read(buffer, 0, 5);

 

    // Deserialize the object from the stream

    data = (BinDataClass^)formatter->Deserialize(NetStream);

 

    Console::WriteLine("Deserialized the following object:");

    data->Print();

 

    // Close up

    Console::WriteLine("Closing all...");

    ListeningSocket->Close();

    NetStream->Close();

    ClientSocket->Close();

 

    return 0;

}

 

Re-build and run the project. If the following Windows Security Alert displayed, unblock it.

 

C++ Binary Server Socket program example - unblocking the Windows firewall  

 

C++ Binary Server Socket program example - a sample output without any argument

 

We need to run this program at the command prompt, to see its functionalities. Take note that, you must copy the DLL together with the executable. The following are the sample outputs.

 

C++ Binary Server Socket program example - running the server program with IPv4 arguments, waiting for connections

 

C++ Binary Server Socket program example - running the server program with IPv6 arguments, waiting for connections

 

We will test this server program using the client program that will be created in the next example. A completed code for this part is given below.

 

// SocketBinaryServerCP.cpp : main project file.

 

#include "stdafx.h"

 

using namespace System;

using namespace System::Net;

using namespace System::Net::Sockets;

using namespace System::Runtime::Serialization;

using namespace System::Runtime::Serialization::Formatters::Binary;

using namespace BinDataCP;

 

static void usage()

{

    Console::WriteLine("executable_file_name [/protocol IPv4|IPv6] [/port num]");

}

 

int main(array<System::String ^> ^args)

{

    int Port = 5150;

    Socket^ ListeningSocket = nullptr;

    Socket^ ClientSocket = nullptr;

    IPEndPoint^ LocalEndPoint = nullptr;

    NetworkStream^ NetStream;

    IFormatter^ formatter = gcnew BinaryFormatter();

    BinDataClass^ data;

    array<Byte>^ buffer = gcnew array<Byte>(5);

    // Default is IPv4

    AddressFamily^ ServerAddressFamily = AddressFamily::InterNetwork;

 

            if(args->Length != 0)

            {

                        // Parse the command line

                        for (int i = 0; i < args->Length; i++)

                        {

                                    if (String::Compare(args[i], "/protocol", true) == 0)

                                    {

                                                try

                                                {

                                                            // Create the appropriate listening socket

                                                            Console::WriteLine("Creating the appropriate listening socket...");

                                                            i++;

                                                            if (String::Compare(args[i], "IPv6", true) == 0)

                                                            {

                                                                        ServerAddressFamily = AddressFamily::InterNetworkV6;

                                                                        ListeningSocket = gcnew Socket(

                                                                        AddressFamily::InterNetworkV6,

                                                                        SocketType::Stream,

                                                                        ProtocolType::Tcp

                                                                        );

                                                                        LocalEndPoint = gcnew IPEndPoint( IPAddress::IPv6Any, Port );

                                                                        Console::Write("IPv6 Socket() is OK. IP: {0}, ", IPAddress::IPv6Any);

                                                            }

                                                            else if (String::Compare(args[i], "IPv4", true) == 0)

                                                            {

                                                                        ServerAddressFamily = AddressFamily::InterNetwork;

                                                                        ListeningSocket = gcnew Socket(

                                                                        AddressFamily::InterNetwork,

                                                                        SocketType::Stream,

                                                                        ProtocolType::Tcp

                                                                        );

                                                                        LocalEndPoint = gcnew IPEndPoint(IPAddress::Any, Port);

                                                                        Console::Write("IPv4 Socket() is OK. IP: {0}, ", IPAddress::Any);

                                                            }

                                                            else

                                                            {

                                                                        usage();

                                                                        return 0;

                                                            }

                                                }

                                                catch (IndexOutOfRangeException^)

                                                {

                                                            usage();

                                                            return 0;

                                                }

                                    }

                                    else if (String::Compare(args[i], "/port", true) == 0)

                                    {

                                                try

                                                {

                                                            Port = Convert::ToInt32(args[++i]);

                                                }

                                                catch (IndexOutOfRangeException^)

                                                {

                                                            usage();

                                                            return 0;

                                                }

                                    }

                                    else

                                    {

                                                usage();

                                                return 0;

                                    }

                        }

            }

            else

            {

                        usage();

                        return 0;

            }

 

            Console::WriteLine("Port: " + Port);

            // Bind the socket to the interface we will accept connections one

            ListeningSocket->Bind(LocalEndPoint);

            Console::WriteLine("Bind() looks OK...");

 

            // Set the listen backlog to five

            ListeningSocket->Listen(5);

            Console::WriteLine("Listen() looks OK...");

            Console::WriteLine("I'm listening for connection buddy...");

 

    // Wait until a client connects

    ClientSocket = ListeningSocket->Accept();

    Console::WriteLine("Accept() looks OK...");

 

    // Create a NetworkStream for the accepted client connection

    NetStream = gcnew NetworkStream(ClientSocket);

    Console::WriteLine("Instantiating a NetworkStream...");

 

    // Read the string "hello" from the stream since this was send before the serialized object.

    NetStream->Read(buffer, 0, 5);

 

    // Deserialize the object from the stream

    data = (BinDataClass^)formatter->Deserialize(NetStream);

 

    Console::WriteLine("Deserialized the following object:");

    data->Print();

 

    // Close up

    Console::WriteLine("Closing all...");

    ListeningSocket->Close();

    NetStream->Close();

    ClientSocket->Close();

    return 0;

}

 

C++ Binary Socket Client Program Example

 

The next program example is the client program. Create a new CLR console application. You can use the solution and project names, SocketBinaryClientCP as shown in the following snapshot.

 

C++ Binary Socket Client Program Example - creating a new CLR console application

 

First of all, let add a reference to the classes (shared DLL) created previously so that the related class definition can be found. Select the project folder > Right click mouse > Select the References context menu.

 

C++ Binary Socket Client Program Example - adding a reference to DLL file

 

Click the Add New Reference button.

 

C++ Binary Socket Client Program Example - the references page

 

Browse the BinDataCP.DLL file generated in the previous project.

 

C++ Binary Socket Client Program Example - browsing the DLL file

 

Click the OK button after selecting the BinDataCP.dll file.

 

C++ Binary Socket Client Program Example - selecting the DLL file

 

Add the using namespaces as shown below that include the BinDataCP.

 

using namespace System;

using namespace System::Net;

using namespace System::Net::Sockets;

using namespace System::Runtime::Serialization;

using namespace System::Runtime::Serialization::Formatters::Binary;

using namespace BinDataCP;

 

Build this project to make sure the reference to the class (DLL file) doesn’t have any error.

 

Add the usage() function.

 

/// <summary>

/// Displays usage information for calling the client.

/// </summary>

static void usage()

{

            Console::WriteLine("usage: executable_file_name [/server server-name] [/port port-number]");

            Console::WriteLine("Else, default values will be used...");

            Console::WriteLine();

}

 

Finally, add the main() code.

 

/// <summary>

/// Main application that parses the command line, resolves the server's host name,

/// establishes a socket connection, and serializes the data to the server.

/// </summary>

/// <param name="args">Command line arguments passed to client</param>

int main(array<System::String ^> ^args)

{

    String^ ServerName = L"localhost";

    int Port = 5150;

 

    usage();

 

    // Parse command line arguments if any. However without any argument(s) or wrong

    // argument(s), default will be used: localhost:5150. Well, this just a dummy...

    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 = Convert::ToInt32(args[++i]->ToString());

            }

        }

        catch (IndexOutOfRangeException^)

        {

            usage();

            return 0;

        }

    }

 

    // Attempt to resolve the server name specified

    try

    {

        Socket^ ClientSocket = nullptr;

        IPHostEntry^ IpHost;

        IPEndPoint^ ServerEndPoint;

        String^ ServerAndPort;

 

         IpHost = Dns::GetHostEntry(ServerName);

         Console::WriteLine(L"Server name '{0}' resolved to {1} addresses", ServerName, IpHost->AddressList->Length);

 

        // Walk the array of addresses return and attempt to connect to each

        // one. Take the first successful connection and use it.

        for each (IPAddress^ addr in IpHost->AddressList)

        {

            // Create the endpoint describing the address and port

            ServerEndPoint = gcnew IPEndPoint(addr, Port);

 

            if (ServerEndPoint->AddressFamily == AddressFamily::InterNetwork)

            {

                 ServerAndPort = "IPv4 - [" + addr + "]:" + Port;

            }

            else

            {

                ServerAndPort = "IPv6 - [" + addr + "]:" + Port;

            }

 

            Console::WriteLine("Attempting connection to {0}", ServerAndPort);

            // Create a socket and attempt to connect to the endpoint

            ClientSocket = gcnew Socket(ServerEndPoint->AddressFamily, SocketType::Stream, (ProtocolType)0);

 

            try

            {

                ClientSocket->Connect(ServerEndPoint);

            }

            catch (SocketException^ err)

            {

                Console::WriteLine(L"Connection attempt to {0} failed: {1}", ServerAndPort, err->Message);

                ClientSocket->Close();

                ClientSocket = nullptr;

                continue;

            }

            break;

        }

        // Make sure we have a valid socket connection before continuing

        if ((ClientSocket != nullptr) && (ClientSocket->Connected == true))

        {

            String^ s = L"Hello";

            array<Byte>^ buf = System::Text::Encoding::ASCII->GetBytes(s->ToCharArray());

            BinDataClass^ binclass;

            NetworkStream^ NetStream;

            IFormatter^ formatter;

 

            binclass = gcnew BinDataClass();

            NetStream = gcnew NetworkStream(ClientSocket);

            formatter = gcnew BinaryFormatter();

 

            try

            {

                // Send some data on socket before serializing the object. The server

                // must consume this data before deserializing the object otherwise a serialization exception will occur.

                ClientSocket->Send(buf);

 

                binclass->Field2 = L"Client - Replaced original text with this message";

                Console::WriteLine(L"Serializing the following object:");

                binclass->Print();

                formatter->Serialize(NetStream, binclass);

            }

            catch (SocketException^ err)

            {

                 Console::WriteLine(L"A socket error occurred: " + err->Message);

            }

            catch (SerializationException^ err)

            {

                  Console::WriteLine("A serialization error occurred: " + err->Message);

            }

            // Free up the resources

            NetStream->Close();

        }

        // Close socket resource. This check needs to be outside the previous

        // control block since its possible a socket was created but the connect call failed.

        if (ClientSocket != nullptr)

        {

            ClientSocket->Close();

            ClientSocket = nullptr;

        }

    }

    catch (SocketException^ err)

    {

        // This will catch DNS errors. If name resolution fails we might as well

        // exit since we don't know the server's address.

        Console::WriteLine("Socket error: " + err->Message);

    }

    return 0;

}

 

Build and run the project.

 

C++ Binary Socket Client Program Example - sample output with default argument values

 

Next, let test this client program with the server program created before. In this case we test both program locally and make sure a copy of the BinDataCP.dll must accompany the executables. Firstly, run the server program.

 

C++ Binary Socket Client Program Example - running the server program and waiting for connection

 

Then run the client program.

 

C++ Binary Socket Client Program Example - running the client program

 

The following screenshot shows the server program when the communication was completed.

 

C++ Binary Socket Client Program Example - the server output when the communication was completed

 

It looks like the server must set the listening socket to specific IP instead of Any (0.0.0.0) as in the following code so that the client can make use the IP address and port number to be connected. You may want to try making the server just listening to one interface instead of any interface as used in the server program.

 

            LocalEndPoint = gcnew IPEndPoint(IPAddress::Any, Port);

 

 

 


 

< VB .NET Binary SOAP Program Example | Main | C# Binary Socket Server Program Example >