|
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("127.0.0.1", 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))
Else
If Not networkStream.CanRead Then
Console.WriteLine("cannot not write data to this stream")
tcpClient.Close()
Else
If Not networkStream.CanWrite Then
Console.WriteLine("cannot read data from this stream")
tcpClient.Close()
End If
End If
End If
' pause so user can view the console output
Console.ReadLine()
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)
tcpListener.Start()
Console.WriteLine("Waiting for connection...")
Try
'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. |
|