Home » Software » Creating Simple TCP/IP Server And Client to Transfer Data Using C# / VB.net

Creating Simple TCP/IP Server And Client to Transfer Data Using C# / VB.net

Creating Simple TCP IP Server And Client

A lot of networked applications nowadays choose TCP/IP because there is no risk of data being damaged while traveling across the Internet. Unlike using UDP to transfer file, TCP/IP said to be connection oriented; which, both client and server after a setup phase treat some IP packets as being sent along a virtual route, enabling for data that is too large to fit into a single IP packet to be sent and for retransmission to occur when packets are lost. This sample software will allow you to deliver any file from one computer to another. Again, it is client/server based, so you will need either two computers or to run both the client and server on the same device.

Creating a simple TCP/IP client In C# / VB.net

Create a new project as usual, and build a form as shown image below.

TCP IP Client Application

TCP IP Client Application

Name the Send button btnSend , the Browse button btnBrowse , the File textbox tbFilename , and the Server textbox tbServer . Also add an Open File Dialog control called openFileDialog . Click on the Browse button and put the following code: This code opens the default file open dialog box. If the user does not select a file, openFileDialog.Filename will return an empty string. Click on the Send button and put the following code:

C#

private void btnBrowse_Click(object sender,
System.EventArgs e)
{
openFileDialog.ShowDialog();
tbFilename.Text = openFileDialog.FileName;
}

VB.net

Private Sub btnBrowse_Click(ByVal sender As _
System.Object, ByVal e As System.EventArgs) _
HandlesbtnBrowse.Click
openFileDialog.ShowDialog()
tbFilename.Text = openFileDialog.FileName
end sub

The above code opens the default file open dialog box. If the user doesn’t select a file, openFileDialog.Filename will return an empty string. Click on the Send button and add the following code:

C#

private void btnSend_Click(object sender, System.EventArgs e)
{
Stream fileStream = File.OpenRead(tbFilename.Text);
// Alocate memory space for the file
byte[] fileBuffer = new byte[fileStream.Length];
fileStream.Read(fileBuffer, 0, (int)fileStream.Length);
// Open a TCP/IP Connection and send the data
TcpClient clientSocket = new TcpClient(tbServer.Text,8080);
NetworkStream networkStream = clientSocket.GetStream();
networkStream.Write(fileBuffer,0,fileBuffer.GetLength(0));
networkStream.Close();
}

VB.net

Private Sub btnSend_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnSend.Click
Dim filebuffer As Byte()
Dim fileStream As Stream
fileStream = File.OpenRead(tbFilename.Text)
' Alocate memory space for the file
ReDim filebuffer(fileStream.Length)
fileStream.Read(filebuffer, 0, fileStream.Length)
' Open a TCP/IP Connection and send the data
Dim clientSocket As New TcpClient(tbServer.Text, 8080)
Dim networkStream As NetworkStream
networkStream = clientSocket.GetStream()
networkStream.Write(filebuffer, 0, fileStream.Length)
end sub

The above code reads in a file and sends it over a network connection. To read in a file, a stream for this file is created by passing the filename to the OpenRead method. This stream is read into the file buffer array. An alternate means of reading this file would be to pass the file stream as a parameter to the constructor of a StreamReader, then to call the ReadToEnd method, although this approach would only be useful for text-only files.

It then opens a TCP/IP connection with the server on port 8080, as specified in tbServer.Text. The TcpClient constructor is blocking, in that code execution will not continue until a connection is established. If a connection cannot be created, a SocketException will be thrown: “No connection could be made because the target machine actively refused it.” As usual, the following assemblies are included:

C#

using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.IO;

 

VB.net

imports System.Threading
imports System.Net
imports System.Net.Sockets
imports System.Text
imports System.IO

List below the significant methods and properties for TcpClient.

  • Constructor – Initializes a new instance of the TcpClient class. It may be used thus: new TcpClient(string,Int).
  • NoDelay – When set to true, it increases efficiency if your software application only transmits small amounts of data in bursts. Returns Bool.
  • ReceiveBufferSize – Gets or sets the size of the receive buffer. Returns Int.
  • SendBufferSize – Gets or sets the size of the send buffer. Returns Int.
  • SendTimeout – Gets or sets the amount of time a TcpClient will wait to receive confirmation after you initiate a send. Returns Int.
  • Close() – Closes the TCP connection.
  • Connect() – Connects the client to a remote TCP host using the specified host name and port number. It may be invoked thus: Connect(string,Int).
  • GetStream() – Returns the stream used to send and receive data. Returns NetworkStream.

 

Creating a simple TCP/IP server In C# / VB.net

Open a new project as before, and design a user interface as depicted in image below.

TCP IP Server Application

TCP IP Server Application

The label should be named lblStatus, and the list box, lbConnections. Like the UDP server, the TCP server is multithreaded. In such a case, three threads are used: the main thread maintains the user interface, a second thread listens for connections, and a third thread handles the connections. One socket is needed for each connection and will remain loaded in memory until the connection is closed.

These sockets need to be stored in an ArrayList rather than a standard array because it is impossible to predict how many connections will be received. To begin with, declare a global ArrayList variable:

C#

public class Form1 : System.Windows.Forms.Form
{
private ArrayList nSockets;

VB.net

Public Class Form1 Inherits System.Windows.Forms.Form
private nSockets as ArrayList

Because any client wishing to connect to this server would need to know its IP address, it is helpful to display this on-screen. This is a cosmetic feature, but it may come in handy in other applications. To be able to retrieve the local IP address, we call the static method Dns.GetHostByName. This returns an IPHostEntry object, which is a collection of IP addresses, to provide multihomed computers, which many are. Element zero in this array is normally the external IP address for the computer.

The Form1_Load method displays the local IP address on the form and starts the thread that will wait for incoming connections. If the listenerThread method were to be called immediately, the application would become unresponsive and seem to hang, while the socket waited on inbound connections. This effect is avoided by performing the listenerThread method in a separate thread of execution, which can block without adversely affecting the user interface.

C#

private void Form1_Load(object sender, System.EventArgs e)
{
IPHostEntry IPHost = Dns.GetHostByName(Dns.GetHostName());
lblStatus.Text = "My IP address is " +
IPHost.AddressList[0].ToString();
nSockets = new ArrayList();
Thread thdListener = new Thread(new
ThreadStart(listenerThread));
thdListener.Start();
}

VB.net

Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Dim IPHost as IPHostEntry
IPHost = Dns.GetHostByName(Dns.GetHostName())
lblStatus.Text = "My IP address is " + _
IPHost.AddressList(0).ToString()
nSockets = new ArrayList()
Dim thdListener As New Thread(New ThreadStart _
(AddressOf listenerThread))
thdListener.Start()
End Sub

The listenerThread method’s function is to wait indefinitely for TCP connections on port 8080 and then to redelegate the work of handling these requests to the handlerThread method. This function also reports the source of the connections. This time, the explanation for redelegating work to a thread is not to maintain the responsiveness of the user interface, but rather to ensure that the software will continue to listen for new connections while it is handling a previous client.

The new thread will be needed to have access to the socket that is dealing with the current client. Otherwise, there would be no means of returning data. This thread will stop on the call to AcceptSocket. Execution will not continue until an incoming connection has been detected; when it has, a new socket is created and dedicated to handling this particular client. As soon as this socket has established a connection, the socket is placed on top of the nSockets array list to await pickup by the handler thread. It may seem strange that the socket is not passed directly to the thread. This is because it is not valid to specify parameters when defining the starting point of a thread, for example, making an erroneous statement such as

New ThreadStart(AddressOf handlerThread(Parameter))

Therefore, another means of passing parameters to threads is required. In this example, a public array list of sockets is used, where the top-most entry is used by the newest thread, and so forth. Another popular technique for passing parameters to threads is to encapsulate the thread’s methods in a different class, with public variables acting as parameters. When a new instance of this class is created, it can be passed to the ThreadStart constructor.

Once the socket has been added to the array list, the handler thread is invoked, and this thread keeps to listen for incoming connections.

C#

public void listenerThread()
{
TcpListener tcpListener = new TcpListener(8080);
tcpListener.Start();
while(true)
{
Socket handlerSocket = tcpListener.AcceptSocket();
if (handlerSocket.Connected)
{
lbConnections.Items.Add(
handlerSocket.RemoteEndPoint.ToString() + " connected."
);
lock (this)
{
nSockets.Add(handlerSocket);
}
ThreadStart thdstHandler = new
ThreadStart(handlerThread);
Thread thdHandler = new Thread(thdstHandler);
thdHandler.Start();
}
}
}

VB.net

Public sub listenerThread()
Dim tcpListener as new TcpListener(8080)
Dim handlerSocket as Socket
Dim thdstHandler as ThreadStart
Dim thdHandler as Thread
tcpListener.Start()
do
handlerSocket = tcpListener.AcceptSocket()
if handlerSocket.Connected then
lbConnections.Items.Add( _
handlerSocket.RemoteEndPoint.ToString() + _
"connected.")
SyncLock (Me)
nSockets.Add(handlerSocket)
end SyncLock
thdstHandler = New ThreadStart(AddressOf _
handlerThread)
thdHandler = New Thread(thdstHandler)
thdHandler.Start()
end if
Loop
End sub

The rest of the work is carried out in the handlerThread method. This function finds the last used socket and then retrieves the stream from this socket. An array is allocated to the same size as the stream, and once the stream is completely obtained, its information are copied into this array. As soon as the connection closes, the data is written to file at c:\my documents\SubmittedFile.txt. It is important to have the lock() keyword around the lines of code associated with file access; otherwise, if two concurrent connections try to access the same file, the application will crash. The contents of the file are then shown in the list box on-screen.

The socket is then set to null to remove it from memory. If this point were omitted, the array list would quickly fill with sockets that had lost connection with their clients. Note that the constructor for TcpListener that takes only a single int for a port number is now obsolete. To prevent the compiler complaining about this line of code, simply call the constructor thus:

new TcpListener(IPAddress.Any,8080)

C#

public void handlerThread()
{
Socket handlerSocket = (Socket)nSockets[nSockets.Count-1];
NetworkStream networkStream = new
NetworkStream(handlerSocket);
int thisRead=0;
int blockSize=1024;
Byte[] dataByte = new Byte[blockSize];
lock(this)
{
// Only one process can access
// the same file at any given time
Stream fileStream = File.OpenWrite("c:\\my documents\
\SubmittedFile.txt");
while(true)
{
thisRead=networkStream.Read(dataByte,0,blockSize);
fileStream.Write(dataByte,0,thisRead);
if (thisRead==0) break;
}
fileStream.Close();
}
lbConnections.Items.Add("File Written");
handlerSocket = null;
}

VB.net

Public Sub handlerThread()
Dim handlerSocket As Socket
handlerSocket = nSockets(nSockets.Count - 1)
Dim networkStream As NetworkStream = New _
NetworkStream(handlerSocket)
Dim blockSize As Int16 = 1024
Dim thisRead As Int16
Dim dataByte(blockSize) As Byte
SyncLock Me
' Only one process can access the
' same file at any given time
Dim fileStream As Stream
fileStream = File.OpenWrite("c:\SubmittedFile.txt")
While (True)
thisRead = networkStream.Read(dataByte, _
0, blockSize)
fileStream.Write(dataByte, 0, dataByte.Length)
If thisRead = 0 Then Exit While
End While
fileStream.Close()
End SyncLock
lbConnections.Items.Add("File Written")
handlerSocket = Nothing
End Sub

Like before, put the namespace references to the head of the code:

C#

using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.IO;

VB.net

imports System.Threading
imports System.Net
imports System.Net.Sockets
imports System.Text
imports System.IO

To test the application, run the server application, and take note of the IP address displayed. Then, run the client application. Type the IP address into the box provided. Click on browse to select a file. Press send to transfer the file. A file will soon appear on the server at c:\my documents\SubmittedFile.txt, which is an exact copy of the file that was located on the client.

To further illustrate this concept, you can use a telnet program to write text to c:\SubmittedFile.txt remotely. On Windows 95, 98, or ME machines, click Start→Run, then type Telnet. Click Connect→Remote System. Type the server IP address into the host name textbox, and type 8080 into the port textbox. Press Connect. Type some text into the window, and when finished, press Connect, Disconnect. A file will soon appear on the server at c:\my documents\ SubmittedFile.txt. On Windows NT, 2000, and XP machines, click Start→Run, then type Telnet. Type Open 127.0.0.1 8080. Replace 127.0.0.1 with the IP address of your server, if you have two computers.

Type some text into the window, and when finished, close the window. A file will soon show up on the server at c:\SubmittedFile.txt. Ways have already been developed to send files through the Internet. Anybody who has ever written a Web site would be familiar with programs such as cuteFTP and smartFT, albeit with a much more adjustable interface. It is rarely a good idea to try to recreate the wheel and develop a new way to send data through the Internet. The global standardization of protocols has made the Internet what it is today.

Subscribe