< C# Asynchronous I/O Program Example | Main | C# & VB .NET Thread and Network I/O Examples >

 


 

Chapter 3 Part 9:

Threading and the Asynchronous Pattern

 

 

What do we have in this chapter 3 Part 9?

  1. VB .NET Asynchronous I/O Program Example

  2. C++ Thread and Network I/O Program Example

 

 

VB .NET Asynchronous I/O Program Example

 

Create a new class library project and you can use the solution and project name as shown in the following snapshots.

 

VB .NET Asynchronous I/O Program Example - a new class library project creation

 

Add the following codes.

 

Imports System

Imports System.Net

Imports System.Net.Sockets

 

' This sample is a revision of the NetworkStream Server sample in

' Chapter 02. This server is designed to accept multiple connections

' and demonstrates how to use the NetworkStream class to perform IO between

' 2 sockets. This application performs IO asynchronously by using the BeginXXX

' and EndXXX asynchronous IO pattern. The original sample only accepted 1

' connection and processed IO synchronously. Because this application processes

' IO asynchronously, the application is capable of handling multiple connections at the same time.

'

' To run this sample, simply just run the program without parameters and

' it will listen for a client connection on TCP port 5150. If you want to

' use a different port than 5150 then you can optionally supply a command

' line parameter "/port <port number>" and the listening socket will use your port instead.

 

Public Class Class1

    Shared Sub Main()

        Dim Port As Integer = 5150

 

        ' Parse command line arguments if any

        Dim args As String() = Environment.GetCommandLineArgs()

        Dim i As Integer

 

        For i = 0 To args.Length - 1

            Try

                If (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: Receiver [/port <port number>]")

                Exit Sub

            End Try

        Next

 

        Dim ServerSocket As Socket = Nothing

        Dim ListeningSocket As Socket = Nothing

 

        Try

            ' Setup a listening Socket to await a connection from a peer socket.

            ListeningSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP)

            Console.WriteLine("Socket() is OK...")

            Dim ListeningEndPoint As IPEndPoint = New IPEndPoint(IPAddress.Any, Port)

            Console.WriteLine("IPEndPoint() is OK...")

            ListeningSocket.Bind(ListeningEndPoint)

            Console.WriteLine("Bind() is OK...")

            ListeningSocket.Listen(5)

            Console.WriteLine("Listen() is OK...")

 

            Console.WriteLine("Awaiting a TCP connection on IP: " _

             + ListeningEndPoint.Address.ToString() _

             + " Port: " _

             + ListeningEndPoint.Port.ToString() _

             + "...")

 

            Dim ConnectionCount As Integer = 0

 

            While (True)

                ServerSocket = ListeningSocket.Accept()

                Console.WriteLine("Accept() is OK...")

                ConnectionCount = ConnectionCount + 1

                Console.WriteLine()

                Console.WriteLine("Connection #" + ConnectionCount.ToString() + " is established and awaiting data...")

                Dim NSH As NetworkStreamHandler = New NetworkStreamHandler(ServerSocket, ConnectionCount)

            End While

        Catch e As SocketException

            Console.WriteLine("Failure to create Sockets: " + e.Message)

            Exit Sub

        Finally

            ' Close the listening socket - we do not plan to handle any additional connections.

            ListeningSocket.Close()

        End Try

    End Sub

 

    Public Class NetworkStreamHandler

        Private Buffer(4096) As Byte

        Private AsyncReceiveCallback As AsyncCallback = New AsyncCallback(AddressOf ProcessReceiveResults)

 

        ' Let's create a network stream to communicate over the connected Socket.

        Private ServerNetworkStream As NetworkStream = Nothing

        Private ConnectionNumber As Integer = 0

 

        Public Sub New(ByVal ServerSocket As Socket, ByVal ConnectionID As Integer)

            ConnectionNumber = ConnectionID

 

            Try

                ' Setup a network stream on the server Socket

                ServerNetworkStream = New NetworkStream(ServerSocket, True)

                Console.WriteLine("NetworkStream() is OK...")

                ServerNetworkStream.BeginRead(Buffer, 0, Buffer.GetUpperBound(0) - 1, AsyncReceiveCallback, Me)

                Console.WriteLine("BeginRead() is OK...")

            Catch e As Exception

                Console.WriteLine(e.Message)

            End Try

        End Sub

 

        Shared Sub ProcessReceiveResults(ByVal ar As IAsyncResult)

            Dim NSH As NetworkStreamHandler = ar.AsyncState

 

            Try

                Dim BytesRead As Integer = 0

                BytesRead = NSH.ServerNetworkStream.EndRead(ar)

                Console.WriteLine("Connection #" + NSH.ConnectionNumber.ToString() _

                 + " received " + BytesRead.ToString() + " byte(s).")

 

                If (BytesRead = 0) Then

                    Console.WriteLine("Connection #" + NSH.ConnectionNumber.ToString() + " is closing.")

                    NSH.ServerNetworkStream.Close()

                    Exit Sub

                End If

                NSH.ServerNetworkStream.BeginRead(NSH.Buffer, 0, NSH.Buffer.GetUpperBound(0) - 1, NSH.AsyncReceiveCallback, NSH)

 

            Catch e As Exception

                Console.WriteLine("Failed to read from a network stream with error: " + e.Message)

                NSH.ServerNetworkStream.Close()

            End Try

        End Sub

    End Class

End Class

 

Build and run the project. The following is a sample output.

 

VB .NET Asynchronous I/O Program Example - a sample output that shows the receiver is waiting for connections

 

To verify the functionalities, let run two clients. The clients are the previously created programs: NetworkStreamSampleVBSender.exe and NetworkStreamSampleCSSender.exe.

Firstly, run the receiver, AsyncNetworkIOCS.exe. Then, run the senders. The following is a sample outputs for two senders and the receiver.

In this case we test on the local host. You may want to test these sender/receiver programs on different hosts which mean the receiver and senders are on different hosts.

 

VB .NET Asynchronous I/O Program Example - a sample outputs that show several clients connected to the server/receiver

 

C++ Thread and Network I/O Program Example

 

Create a new CLR console application project and you might want to use ThreadNetworkIOCP for the project and solution names as shown below.

 

C++ Thread and Network I/O Program Example - a new CLR console application project creation

 

Add the following code.

 

// ThreadNetworkIOCP.cpp : main project file.

// <summary>

// This sample is a revision of the NetworkStream Server sample in

// Chapter 02. This server is designed to accept multiple connections

// and demonstrates how to use the NetworkStream class to perform IO between

// 2 sockets. This application performs IO asynchronously by using threads

// where a thread is created for each connection and IO is processed

// synchronously in each thread. The original sample only accepted 1

// connection and processed IO synchronously. Because this application

// processes IO synchronously using 1 thread per connection, the application

// is capable of handling multiple connections at the same time.

//

// To run this sample, simply just run the program without parameters and

// it will listen for a client connection on TCP port 5150. If you want to

// use a different port than 5150 then you can optionally supply a command

// line parameter "/port <port number>" and the listening socket will use

// your port instead.

// </summary>

 

#include "stdafx.h"

 

using namespace System;

using namespace System::Net;

using namespace System::Net::Sockets;

using namespace System::Threading;

 

public ref class NetworkStreamHandler

{

    // Let's create a network stream to communicate over the connected Socket.

    static NetworkStream^ ServerNetworkStream = nullptr;

    static int ConnectionNumber = 0;

 

public: NetworkStreamHandler(Socket^ ServerSocket, int ConnectionID)

    {

        ConnectionNumber = ConnectionID;

        try

        {

            // Setup a network stream on the server Socket

            ServerNetworkStream = gcnew NetworkStream(ServerSocket, true);

            Console::WriteLine("NetworkStream() is OK...");

        }

        catch (Exception^ e)

        {

              Console::WriteLine("Network stream failed with error: " + e->Message);

        }

 

        try

        {

            ThreadStart^ NetworkThreadMethod = gcnew ThreadStart(this, &NetworkStreamHandler::ThreadHandlerMethod);

            Console::WriteLine("ThreadStart() is OK...");

            Thread^ NetworkThread = gcnew Thread(NetworkThreadMethod);

            Console::WriteLine("Thread() is OK...");

            NetworkThread->Start();

            Console::WriteLine("Start() is OK...");

        }

        catch (Exception^ e)

        {

            Console::WriteLine("The network thread failed with error: " + e->Message);

            ServerNetworkStream->Close();

        }

    }

 

void ThreadHandlerMethod()

    {

        try

        {

            array< Byte >^ Buffer = gcnew array< Byte >(4096);

            int BytesRead = 0;

 

            do

            {

                BytesRead = ServerNetworkStream->Read(Buffer, 0, Buffer->Length);

                Console::WriteLine();

                Console::WriteLine("Connection #" + ConnectionNumber.ToString() + " received " + BytesRead.ToString() + " byte(s).");

            }

            while (BytesRead > 0);

 

        }

        catch (ThreadAbortException^ e)

        {

              Console::WriteLine("Caught thread abort exception: " + e->Message);

        }

        catch (Exception^ e)

        {

               Console::WriteLine("Thread routine failed with error: " + e->Message);

        }

        finally

        {

            Console::WriteLine("Connection #" + ConnectionNumber.ToString() + " is closing.");

            ServerNetworkStream->Close();

        }

    }

};

 

// <summary>

// The main entry point for the application.

// </summary>

[STAThread]

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

{

    // Default port number, with localhost as listener

    int Port = 5150;

 

    Environment::GetCommandLineArgs();

 

            // Parse command line arguments if any

            if(args->Length != 2)

            {

                        Console::WriteLine("Usage: {0} [/port <port number>]", Environment::CommandLine);

                        return 0;

            }

 

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

            {

                try

                 {

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

                          {

                               // The port on which the server is listening

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

                           }

                 }

         // This just redundant...

        catch (IndexOutOfRangeException^)

        {

            Console::WriteLine("Usage: {0} [/port <port number>]", Environment::CommandLine);

            return 0;

        }

    }

 

    Socket^ ServerSocket = nullptr;

    Socket^ ListeningSocket = nullptr;

 

    try

    {

        // Setup a listening Socket to await a connection from a peer socket.

        ListeningSocket = gcnew Socket(AddressFamily::InterNetwork, SocketType::Stream, ProtocolType::IP);

        Console::WriteLine("Socket() is OK...");

        // Listening on all interface...

        IPEndPoint^ ListeningEndPoint = gcnew IPEndPoint(IPAddress::Any, Port);

        Console::WriteLine("IPEndPoint() is OK...");

        ListeningSocket->Bind(ListeningEndPoint);

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

        ListeningSocket->Listen(5);

        Console::WriteLine("Listen() is OK, I\'m listening for connection...");

 

        Console::WriteLine("Awaiting TCP connections on IP: "

                                    + ListeningEndPoint->Address->ToString()

                                    + " Port: "

                                    + ListeningEndPoint->Port.ToString()

                                    + "...");

 

        int ConnectionCount = 0;

 

        while (true)

        {

            ServerSocket = ListeningSocket->Accept();

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

            ConnectionCount++;

            Console::WriteLine("Connection #" + ConnectionCount.ToString() + " is established and awaiting data...");

            NetworkStreamHandler^ NSH = gcnew NetworkStreamHandler(ServerSocket, ConnectionCount);

            Console::WriteLine("NetworkStreamHandler() is OK...");

        }

    }

    catch (SocketException^ e)

    {

            Console::WriteLine("Failure to create Sockets: " + e->Message);

    }

    finally

    {

        // Close the listening socket - we do not plan to handle any additional connections.

        Console::WriteLine("Closing a listening socket...");

        ListeningSocket->Close();

    }

return 0;

}

 

Build and run the project. Unblock the connection if any.

 

C++ Thread and Network I/O Program Example - unblocking the Windows firewall  

 

The following is the output sample that using port number 8181 and listening to any interfaces of the localhost. The receiver is waiting for connection.

 

C++ Thread and Network I/O Program Example - a sample output that shows the receiver is waiting for connection

 

Next, let test sending some messages from three clients to the receiver. We use the previously created sender program examples: networkstreamsamplecpsender (C++), networkstreamsamplevbsender (VB .NET) and networkstreamsamplecssender (C#).

 

C++ Thread and Network I/O Program Example - a sender in action

 

C++ Thread and Network I/O Program Example - another sender in action

 

C++ Thread and Network I/O Program Example - more sender in action

 

The following is the output sample when the communication was completed.

 

C++ Thread and Network I/O Program Example - a receiver/server in action when the communication was completed

 

 

 


 

< C# Asynchronous I/O Program Example | Main | C# & VB .NET Thread and Network I/O Examples >