VB.NET TCP Client - Server Socket Communications

By Peter A. Bromberg, Ph.D.
Printer Friendly Version

Peter Bromberg

Often we need to use TCP over IP sockets to do communications instead of the familiar HTTP protocol that web developers are used to. Prior to the arrival of the .NET platform, this usually involved a ton of Winsock code and C - style API declarations. I recently had to rewrite a TCP socket client class from VB 6.0 into .NET for communication to a mainframe system.

I knew that if I ran the original VB 6.0 DLL project through the VB.NET Migration Wizard that I'd get a bunch of Winsock "GLOP" and of course that is precisely what I got. Pretty much useless for migration purposes.

Fortunately, there is a whole range of new base classes in System.Net.Sockets that provide a rich set of functionality, abstracting much of the lower - level Windows Sockets API and making it much easier to write code like this. In fact, I was amazed to see that when I had finished I had thown away literally hundreds of lines of legacy VB 6.0 Winsock - related code and the final working version of my TCP client class was only about 40 lines - including a function to accept an XML document as a string and forward it on to the listener, and get back the result!

Here's a sample TCP Client and associated server "listener" to illustrate how easy socket programming has become in .NET. I'm keeping this synchronous and very basic; the idea is you have a client that accepts an input message, makes a connection to the listener on a specific address and port, sends the message, and retrieves the response. The sockets are then closed. These are console apps so you can easily see what's going back and forth, but it is trivial to compile the client code into a class library to allow multithreaded socket messaging even from ASPX pages, assuming that a listener exists that is equipped to handle the incoming requests correctly without serializing them.

Typically a server - listener of this type would listen on a single port but spin off separate sockets for each received message that comes in.

First, lets look at the code for a client:

Imports System.Net.Sockets
Imports System.Text
Class TCPCli
    Shared Sub Main()

        Dim tcpClient As New System.Net.Sockets.TcpClient()
        tcpClient.Connect("", 8000)
        Dim networkStream As NetworkStream = tcpClient.GetStream()
        If networkStream.CanWrite And networkStream.CanRead Then
            ' Do a simple write.
            Dim sendBytes As [Byte]() = Encoding.ASCII.GetBytes("Is anybody there")
            networkStream.Write(sendBytes, 0, sendBytes.Length)
            ' Read the NetworkStream into a byte buffer.
            Dim bytes(tcpClient.ReceiveBufferSize) As Byte
            networkStream.Read(bytes, 0, CInt(tcpClient.ReceiveBufferSize))
            ' Output the data received from the host to the console.
            Dim returndata As String = Encoding.ASCII.GetString(bytes)
            Console.WriteLine(("Host returned: " + returndata))
            If Not networkStream.CanRead Then
                Console.WriteLine("cannot not write data to this stream")
                If Not networkStream.CanWrite Then
                    Console.WriteLine("cannot read data from this stream")
                End If
            End If
        End If
        ' pause so user can view the console output
    End Sub
End Class

All we're doing here is creating a new TcpClient, calling its Connect method, and then getting access to its underlying NetworkStream via the GetStream() method. We Write our message into the stream (converted to a byte array first) and then Read the response from the server. When done, we close the socket. And now, on the server side:

Imports System.Net.Sockets
Imports System.Text
Class TCPSrv
    Shared Sub Main()
        ' Must listen on correct port- must be same as port client wants to connect on.
        Const portNumber As Integer = 8000
        Dim tcpListener As New TcpListener(portNumber)
        Console.WriteLine("Waiting for connection...")
            'Accept the pending client connection and return 
'a TcpClient initialized for communication. Dim tcpClient As TcpClient = tcpListener.AcceptTcpClient() Console.WriteLine("Connection accepted.") ' Get the stream Dim networkStream As NetworkStream = tcpClient.GetStream() ' Read the stream into a byte array Dim bytes(tcpClient.ReceiveBufferSize) As Byte networkStream.Read(bytes, 0, CInt(tcpClient.ReceiveBufferSize)) ' Return the data received from the client to the console. Dim clientdata As String = Encoding.ASCII.GetString(bytes) Console.WriteLine(("Client sent: " + clientdata)) Dim responseString As String = "Connected to server." Dim sendBytes As [Byte]() = Encoding.ASCII.GetBytes(responseString) networkStream.Write(sendBytes, 0, sendBytes.Length) Console.WriteLine(("Message Sent /> : " + responseString)) 'Any communication with the remote client using the TcpClient can go here. 'Close TcpListener and TcpClient. tcpClient.Close() tcpListener.Stop() Console.WriteLine("exit") Console.ReadLine() Catch e As Exception Console.WriteLine(e.ToString()) Console.ReadLine() End Try End Sub End Class

As can be seen, the server creates a new instance of the TcpListener class on the port, and calls the Start() method. It then calls the AcceptTcpClient() method which returns a TcpClient that you can use to send and receive data. Use TcpClient.GetStream to obtain the underlying NetworkStream of the TcpClient. NetworkStream inherits from Stream, which provides a rich collection of methods and properties for network communications ( If you want greater flexibility than a TcpClient offers, consider using AcceptSocket.).

We do a Read to get the sent data, and we can also call networkStream.Write() to send back a response. That's pretty much it for sending data over TCP sockets in .NET! Its easy, simple, and very extensible. You can download a VB.NET solution with projects for both the Client and the Server (listener) at the link below.

Download the code that accompanies this article

Peter Bromberg is a C# MVP, MCP, and .NET consultant who has worked in the banking and financial industry for 20 years. He has architected and developed web - based corporate distributed application solutions since 1995, and focuses exclusively on the .NET Platform.