Jan 15, 2011. 5:15 PM
This blog post is a client/server file sharing or transfer application in C#, the application is made up of two projects, it can be tested on a single computer but its capability will be best seen if tested on two computers, one running as a client while the other is a server.
Before we dive into coding, it is essential to understand Socket
which is the most important aspect of network programming.
Socket
is an object that represents a low level access point to the Internet Protocol(IP) stack, it is used to send and receive data, thus it can be opened and closed, the data to be sent is always sent in block known as Packet.
Packets must contain the IP address of both the source of the packets and the destination computer where the data is being sent, and optionally it may contain a Port number. A port number is between 1 and 65,535. A port is a communication channel or endpoints on which computers can communicate. It is always recommended that programs use port number higher than 1024 to avoid conflicts with other applications running on the system, because no two applications can use the same port.
Packets containing port numbers can be sent using UDP (User Datagram Protocol) or TCP/IP(Transmission control protocol). UDP is easier to use than TCP because TCP is more complex and has longer latencies, but when the integrity of the data to be transferred is more important than performance, then TCP is preferred to UDP, and thus for our file sharing application TCP/IP will be used because it guarantees that our file does not become corrupt while being transferred and if during the transmission process a packet is loss, it is retransmitted thus making sure that our file integrity is maintained.
Thus, this application will allow you to send any file from one computer to another, personally I have used it to send a 350MB file from one desktop PC to another.
Now to get started, create two new Windows Forms applications. one named FileSharingServer
and the other FileSharingClient
.
Now, for the FileSharingClient
Windows Form application, add three textboxes and two buttons to the form just like the screen below:
Rename the textboxes and buttons appropriately.
This is the code for the file sharing client application:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.IO;
namespace FileSharingClient
{
public partial class Form1 : Form
{
private static string shortFileName = "";
private static string fileName = "";
public Form1()
{
InitializeComponent();
}
private void btnBrowse_Click(object sender, EventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Title = "File Sharing Client";
dlg.ShowDialog();
txtFile.Text = dlg.FileName;
fileName = dlg.FileName;
shortFileName = dlg.SafeFileName;
}
private void btnSend_Click(object sender, EventArgs e)
{
string ipAddress = txtIPAddress.Text;
int port = int.Parse(txtHost.Text);
string fileName = txtFile.Text;
Task.Factory.StartNew(() => SendFile(ipAddress,port,fileName,shortFileName) );
MessageBox.Show("File Sent");
}
public void SendFile(string remoteHostIP, int remoteHostPort,
string longFileName, string shortFileName)
{
try
{
if (!string.IsNullOrEmpty(remoteHostIP))
{
byte[] fileNameByte = Encoding.ASCII.GetBytes(shortFileName);
byte[] fileData = File.ReadAllBytes(longFileName);
byte[] clientData = new byte[4 + fileNameByte.Length + fileData.Length];
byte[] fileNameLen = BitConverter.GetBytes(fileNameByte.Length);
fileNameLen.CopyTo(clientData, 0);
fileNameByte.CopyTo(clientData, 4); fileData.CopyTo(clientData, 4 + fileNameByte.Length);
TcpClient clientSocket = new TcpClient(remoteHostIP, remoteHostPort);
NetworkStream networkStream = clientSocket.GetStream();
networkStream.Write(clientData, 0, clientData.GetLength(0));
networkStream.Close();
}
}
catch
{
}
}
}
}
}
Note the following namespaces were added to the Windows Form application:
System.Threading.Tasks;
System.Net;
System.Net.Sockets;
System.Net.NetworkInformation;
The above three namespaces contain the .NET classes used for Network programming.
System.IO;
When the browse button is clicked, an object of OpenFileDialog
is created to open a dialog to get the file name of the file to be sent. When the send button is clicked, the SendFile
method is called and handled in parallel so that the main form user interface does not get frozen while the file is being sent and the processors are fully utilized in a multi-core environment.
The SendFile
method accepts IP address and port number of the destination computer as well as the file path and file name. Both the file name and the file are converted to bytes and sent to the destination computer using the TCPCLient
and NetworkStream
classes object created.
The user interface of the file sharing client application is shown below when run.
The source code for the server is:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.IO;
using System.Threading.Tasks;
namespace FileSharingServer
{
public partial class Form1 : Form
{
public delegate void FileRecievedEventHandler(object source, string fileName);
public event FileRecievedEventHandler NewFileRecieved;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.NewFileRecieved+=new FileRecievedEventHandler (Form1_NewFileRecieved);
}
private void Form1_NewFileRecieved(object sender, string fileName)
{
this.BeginInvoke( new Action( delegate()
{ MessageBox.Show("New File Received\n"+fileName);
System.Diagnostics.Process.Start("explorer", @"c:\");
}));
}
private void btnListen_Click(object sender, EventArgs e)
{
int port = int.Parse(txtHost.Text);
Task.Factory.StartNew(() => HandleIncomingFile(port));
MessageBox.Show("Listening on port"+port);
}
public void HandleIncomingFile(int port)
{
try
{
TcpListener tcpListener = new TcpListener(port);
tcpListener.Start();
while (true)
{
Socket handlerSocket = tcpListener.AcceptSocket();
if (handlerSocket.Connected)
{
string fileName = string.Empty;
NetworkStream networkStream = new NetworkStream(handlerSocket);
int thisRead = 0;
int blockSize = 1024;
Byte[] dataByte = new Byte[blockSize];
lock (this)
{
string folderPath = @"c:\";
int receivedBytesLen = handlerSocket.Receive(dataByte);
int fileNameLen = BitConverter.ToInt32(dataByte, 0);
fileName = Encoding.ASCII.GetString(dataByte, 4, fileNameLen);
Stream fileStream = File.OpenWrite(folderPath + fileName);
fileStream.Write(dataByte, 4+fileNameLen,(1024-(4+fileNameLen)));
while (true)
{
thisRead = networkStream.Read(dataByte, 0, blockSize);
fileStream.Write(dataByte, 0, thisRead);
if (thisRead == 0)
break;
}
fileStream.Close();
}
if (NewFileRecieved != null)
{
NewFileRecieved(this, fileName);
}
handlerSocket = null;
}
}
}
catch { }
}
}
}
At the file sharing server application, a port number is supplied, on which the server will be listening to an income file to be received.
Just like the file sharing client application, the start listening button when clicked, invokes the HandleIncomingFile
method in parallel. A TcpListener
object is created to start listening for incoming file at the specified port, when a connection is received then a file with the same name as the file sent from the client is reconstructed from the received bytes and saved to the C drive and then an event is fired to indicate on the server user interface that a new file has been received.
When the event is fired, all subscribers to the event are notified and in this case the event handler method Form1_NewFileRecieved
is invoked and the code to display a message box and open the folder containing the file received is wrapped around the form BeginInvoke
method to avoid thread errors.
The complete source code of the two applications is available for download here.