Showing posts with label File Transfer. Show all posts
Showing posts with label File Transfer. Show all posts

Saturday, February 26, 2011

How to transfer Large File using C# Socket

-->
Now I will discuss about, how we can transfer a large file (file size in GB) using Microsoft dot net socket programming using C# (C sharp) language. This code has written in Visual Studio 2005 (dot net 2).

Source Code
https://drive.google.com/file/d/0Bwd4GP6MNsEgXy1ZZmxFdVFfS0U/view?usp=sharing


Basic Knowledge
To cover this article you need to read my few articles, these are –
1. Asynchronous Socket Server Programming for Beginner
2. Asynchronous Socket Client Programming for Beginner
3. File Transfer using C# Socket Programming
4. Split and Assemble large file (around 2GB) in C# dot net Programming

Steps
The basic code has covered in these article and that article basically comes by assembled these four. To transfer a large file from Client to Server I’ve followed these basic steps-
1) First read the file (slice wise) and store a slice data in a buffer (byte array). How a file can read slice wise, it has covered in my 4th article (Split and Assemble large file (around 2GB) in C#) in file split section. It’s required because TCP buffer is limited so if we try to send a large data then we will get TCP buffer overflow error.
2) Send these buffered data to server using TCP socket object. How it can be done, has covered in 3rd article (File Transfer using C# Socket programming). And for basic idea you can read article 1 & 2.
3) In server side when we starts to receive sliced data from client then we write these data in a file. How this can be done has covered in article 4 (Split and Assemble large file (around 2GB) in C#.net ), in file assemble section.

To receive file from Server to Client same process is applicable, just then server sends data by sliced and receive by Client in same way.

How to use DLL
In my code I have made these two functionality (server and client) in two separate class library (DLL file). By calling these two libraries (DLL file) any one can transfer data very easily. To do it need to follow these steps -
Step 1: Create Object
To use these dll to transfer data you need to create one client and one server object.
For client object -
SynchronusClient_ByteArr objClient = new SynchronusClient_ByteArr ("","localhost", @"C:\Documents and Settings\Administrator\UserData");
First argument for client id, if you keep it blank string then also ok, but when you use dll for multiple client (sender) to transfer multiple file to multiple client (receiver) then it’s mandatory. Otherwise file may goes to all user or different user. Next argument for server IP, and next for a temporary back up path, it’s require at file receive time from server.
Here and one more constructor with more argument there you can assign port no etc. Here default port is 8000 and 8001.
For Server object –
SyncSocketServerMulClient servObj = new SyncSocketServerMulClient();
If you use this code then server will load it’s default configuration, like port 8000 and 8001 and it’s default path to C: Other wise you can call overloaded method.

Step 2: Method & Properties
For server and client has some method which you need to call.
Client methods and properties are –
Picture 1 Picture 2
Picture 1 for Method and events of client object and Picture 2 for method and property of client class.
Hope from pic 1 you can understand everything very easily and from pic 2 also clear from it’s name. For ‘status’, it holds current status of client like, slicing data, sending data, receiving data etc and ‘progress’ it holds current % of data transfer currently done.
Server methods and properties are –
Picture 3 Picture 4
For pic 3 hope everything clear to you. But my comments here is, when you call start server then server starts and stays active as long as you call stop server. After call start server you can’t call it again before stop server call.
From pic 4 ‘bufferSize’ is for declare byte array length, you can define it as your self, ‘maxClientReceived’ for how many client can send or receive data at a time.
By using this code I’ve developed few large application, like text chat with smiles, file transfer, picture transfer, online drawing etc. Hope you will get a great experience by that code.
Download link
You can download source code from these two links-
http://alap.me/blog/All_Source_Codes.rar


Server Code is here :

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


namespace ServerSockets.Synchronous.UsingByteArray
{

/// That server code will run to access multiple client requrest and response. Here will not any
/// Un-zip and Decript technology. Server will save all data in Encripted-Zipped form which will
/// sent by Client.

public class SyncSocketServerMulClient
{
public static bool isServerRunning=false;
public static int receivePort,sendPort, maxClientReceived, bufferSize;
//public static int progress=0 ;
public string outPath ;
public static string status="",presentOperation = "";
public string currentStatus = "";


public SyncSocketServerMulClient(int receivePort,int sendPort,int maxClient, string outPutPath)
{
SyncSocketServerMulClient.receivePort = receivePort;
SyncSocketServerMulClient.sendPort = sendPort;
SyncSocketServerMulClient.bufferSize = 10 * 1024;
SyncSocketServerMulClient.maxClientReceived = maxClient;

outPutPath = outPutPath.Replace("\\", "/");
if (outPutPath.Substring(outPutPath.Length - 1) != "/")
outPutPath += "/";

this.outPath = outPutPath;
SyncSocketServerMulClient.status = "";
//SyncSocketServerMulClient.progress = 0;
SyncSocketServerMulClient.presentOperation = "";
}

/// Default sets Receive Port:8080, Send Port:8081, Buffer Size:10KB, Max Client:100 and Out path: C:\

public SyncSocketServerMulClient()
{
SyncSocketServerMulClient.receivePort = 8080;
SyncSocketServerMulClient.sendPort = 8081;
SyncSocketServerMulClient.bufferSize = 10 * 1024;
SyncSocketServerMulClient.maxClientReceived = 100;
this.outPath = "c:/";
SyncSocketServerMulClient.status = "";
//SyncSocketServerMulClient.progress = 0;
SyncSocketServerMulClient.presentOperation = "";

}
#region SERVER SYNCHRONOUS SOCKET DATA RECEIVE
Thread threadReceiveServer, threadSendServer;
private void StartReceiveServer()
{
SyncSocketServerMulClient.isServerRunning = true;
threadReceiveServer = new Thread(new ThreadStart(this.StartReceiveServerThread));
threadReceiveServer.Start();
}
private void StopReceiveServer()
{
SyncSocketServerMulClient.isServerRunning = false;
//
try
{

IPAddress[] ipAddress = Dns.GetHostAddresses("localhost");
IPEndPoint ipEnd = new IPEndPoint(ipAddress[0], SyncSocketServerMulClient.receivePort);
Socket clientSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
clientSock.Connect(ipEnd);

string strData = "END";
byte[] clientData = new byte[30];
clientData = Encoding.ASCII.GetBytes(strData);
clientSock.Send(clientData);

//byte[] serverData = new byte[10];
//int len = clientSock.Receive(serverData);
//Console.WriteLine(Encoding.ASCII.GetString(serverData, 0, len));
clientSock.Close();

Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
//
}

Socket receiveSock,sendSock;
IPEndPoint ipEndReceive, ipEndSend;
private void StartReceiveServerThread()
{
ipEndReceive = new IPEndPoint(IPAddress.Any, SyncSocketServerMulClient.receivePort);
receiveSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
receiveSock.Bind(ipEndReceive);
SyncSocketServerMulClient.isServerRunning = true;
receiveSock.Listen(maxClientReceived);
Console.WriteLine("Waiting for new client connection");
while (SyncSocketServerMulClient.isServerRunning)
{
Socket clientSock;
clientSock = receiveSock.Accept();

SyncSocketServerMulClient serObj = new SyncSocketServerMulClient(SyncSocketServerMulClient.receivePort, SyncSocketServerMulClient.sendPort, SyncSocketServerMulClient.bufferSize, this.outPath);
Thread newClient = new Thread(serObj.ReadDataFromClient);
newClient.Start(clientSock);
}
receiveSock.Close();

}
private void ReadDataFromClient(object clientObject)
{
Socket clientSock = null;
BinaryWriter bWriter=null;
string fileName = "";
try
{
SyncSocketServerMulClient.status = "";
SyncSocketServerMulClient.presentOperation = "";
clientSock = (Socket)clientObject;
bool flag = true;
Console.WriteLine("New connection estublished. Socket {0}", clientSock.GetHashCode());
int totalDataLen, receivedLen, fileNameLen, fileContentStartIndex;

byte[] data = new byte[bufferSize];
//DATA FORMAT: [FILE SIZE LEN INFO[0-3]][FILE NAME LEN INFO[4-7]][FILE NAME DATA][FILE CONTENT]



//GET FILE NAME, SIZE ETC.
currentStatus =presentOperation = "Data Receiving";
int len = clientSock.Receive(data);
if (len == 0)
{
clientSock.Close();
return;
}
if (len == 3)
{
string clientData = Encoding.ASCII.GetString(data);
if (clientData.Substring(0, len) == "END")
return;
}
totalDataLen = BitConverter.ToInt32(data, 0);
fileNameLen = BitConverter.ToInt32(data, 4);
fileName = Encoding.ASCII.GetString(data, 8, fileNameLen);
fileContentStartIndex = 4 + 4 + fileNameLen;
receivedLen = len - fileContentStartIndex;
//READ DATA & STORE OF FIRST PACKET

//DELETE IF FILE ALREADY EXIST
if (File.Exists(outPath + fileName))
File.Delete(outPath + fileName);

bWriter = new BinaryWriter(File.Open(outPath + fileName, FileMode.Append));
bWriter.Write(data, 0, len);
while (true)
{
if (receivedLen < len =" clientSock.Receive(data);" currentstatus ="presentOperation" currentstatus =" presentOperation" clientinfodata =" new" clientinfodata =" Encoding.ASCII.GetBytes(" status = "Access Denied by server end." status = "Address Already In Use." status = "Address Not Available." status = "Connection aborted by server." status = "Connection refused by server." status = "Connection Reset." status = "Destination Address Required." status = "Disconnecting." status = "Target Host is Down." status = "Target Host Not Found." status = "Target Host Unreachable." status = "In Progress." status = "Interrupted." status = "Invalid Argument." status = "Network Down." status = "Network Reset." status = "Network Unreachable." status = "No Buffer Space Available." status = "No Data." status = "Not Connected." status = "Not Initialized." status = "Not Socket." status = "Operation Aborted." status = "Socket already Shutdown." status = "Too Many Open Sockets." status = "Too Many Open Sockets." status = "Have some unknown problem in Socket." isserverrunning =" true;" threadsendserver =" new" ipendsend =" new" sendsock =" new" isserverrunning =" true;" clientsock =" sendSock.Accept();" serobj =" new" newclient =" new" clientsocket="(Socket)clientObject;" filenamewithpath = "" breader =" null;" status = "" clientdata =" new" clientdatalen =" clientSocket.Receive(clientData);" clientdatalen ="=" clientdatalen ="=" clientdatastr =" Encoding.ASCII.GetString(clientData);" clientidlen =" BitConverter.ToInt32(clientData," filenamelen=" BitConverter.ToInt32(clientData," clientid =" Encoding.ASCII.GetString(clientData," filename =" Encoding.ASCII.GetString(clientData," copiedfilename =" clientId" filenamewithpath =" this.outPath;" filenamewithpath =" fileNameWithPath.Replace(" length ="=" currentstatus =" presentOperation" breader =" new" data =" new" sentdatasize =" (int)bReader.BaseStream.Length;" data =" new" sentdatasize =" bufferSize;" totalsentdataslot =" 1;" totaldatasize =" (int)bReader.BaseStream.Length;" progress =" (int)(((float)sentDataSize" progress =" (int)(((float)sentDataSize" enddata =" new" sentdatasize =" (int)bReader.BaseStream.Length;" progress =" (int)(((float)sentDataSize" currentstatus =" presentOperation" strfleerr = "ERROR" tempfleerrarr =" Encoding.ASCII.GetBytes(strFleErr);" currentstatus =" presentOperation" status = "Access Denied by server end." status = "Address Already In Use." status = "Address Not Available." status = "Connection aborted by server." status = "Connection refused by server." status = "Connection Reset." status = "Destination Address Required." status = "Disconnecting." status = "Target Host is Down." status = "Target Host Not Found." status = "Target Host Unreachable." status = "In Progress." status = "Interrupted." status = "Invalid Argument." status = "Network Down." status = "Network Reset." status = "Network Unreachable." status = "No Buffer Space Available." status = "No Data." status = "Not Connected." status = "Not Initialized." status = "Not Socket." status = "Operation Aborted." status = "Socket already Shutdown." status = "Too Many Open Sockets." status = "Too Many Open Sockets." status = "Have some unknown problem in Socket." status =" ex.Message;" isserverrunning =" false;" ipaddress =" Dns.GetHostAddresses(" ipend =" new" clientsock =" new" strdata = "END" clientdata =" new" clientdata =" Encoding.ASCII.GetBytes(strData);" serverdata =" new" len =" clientSock.Receive(serverData);" style="font-weight: bold; color: rgb(51, 51, 255);" size="4">Client Code is here:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;

namespace ClientSockets.Synchronous.UsingByteArray // SyncScoketClient_ByteArr_Dll
{

/// Client open a syncronous socket and send file to server, here asynchronous mode becomes by
/// Threading, and here uses Byte Array to transfer data.

public class SynchronusClient_ByteArr
{
public delegate void FileSendCompletedDelegate();
public event FileSendCompletedDelegate FileSendCompleted, FileReceiveCompleted;
public static int progress = 0, portSend, portReceive;
int bufferSize;
public static string status = "", presentOperation = "", ipAddress, outPathDefault = "";
private static string outPathUserSelected = "";
string clientId = "";
string fileNameWithPath;
public static bool isSaveToDefaultPath = false;
static int totalSentDataSlot;

public SynchronusClient_ByteArr(string clientId, string ipAddress, int sendPort, int receivePort, string DefaultPath)
{
this.clientId = clientId;
SynchronusClient_ByteArr.ipAddress = ipAddress;
SynchronusClient_ByteArr.portSend = sendPort;
SynchronusClient_ByteArr.portReceive = receivePort;
SynchronusClient_ByteArr.outPathDefault = DefaultPath;
this.bufferSize = 10 * 1024;
}

/// Conestructor of Client Object

public SynchronusClient_ByteArr(string clientId, string ipAddress, string DefaultPath)
{
this.clientId = clientId;
outPathDefault = DefaultPath;
SynchronusClient_ByteArr.ipAddress = ipAddress;
SynchronusClient_ByteArr.portSend = 8080;
SynchronusClient_ByteArr.portReceive = 8081;
this.bufferSize = 10 * 1024;
}
Thread startFileTransferThread, startFileReceiveThread;
public string SendFileToServer( string senderId, string receiverId)
{

string newFileName, onlyFileName, path;

//Select a File to transfer
OpenFileDialog ofd = new OpenFileDialog();
if (ofd.ShowDialog() != DialogResult.OK)
return "Cancelled by user";
string fileNameWithPath = ofd.FileName;
fileNameWithPath = fileNameWithPath.Replace("\\", "/");
onlyFileName = fileNameWithPath;
path = "";

while (onlyFileName.IndexOf("/") != -1)
{
path += onlyFileName.Substring(0, onlyFileName.IndexOf("/")) + "/";
onlyFileName = onlyFileName.Substring(onlyFileName.IndexOf("/") + 1);
}
newFileName = senderId + "#" + onlyFileName;
//File.Copy(fileNameWithPath, path + "/" + newFileName,true);
//File.SetAttributes(path + "/" + newFileName, FileAttributes.Hidden);

string bothName = fileNameWithPath + "?" + path + "/" + newFileName;
startFileTransferThread = new Thread(this.SendFileToServerByThread);
startFileTransferThread.Start(bothName);

//NEW FILE NAME IS NOW IN IT'S OWN EXTENSION NEED TO CHANGE .sjb FORM
//Only file name
int k = newFileName.Length - 1;
while (newFileName.Substring(k, 1) != ".")
{
k--;
}
newFileName = newFileName.Substring(0, k);
newFileName = newFileName + ".sjb";

return newFileName;
}
private void SendFileToServerByThread(object fileNameWithPathObj)
{
Socket server = null;
BinaryReader bReader = null;
string newFileName = "";
try
{
//BUILD A COPY OF SENDING FILE
string oldFileName, bothFileName;
bothFileName = fileNameWithPathObj.ToString();
oldFileName = bothFileName.Substring(0, bothFileName.IndexOf("?"));
newFileName = bothFileName.Substring(bothFileName.IndexOf("?") + 1);

string filePath = "", tempFileName = oldFileName;
while (tempFileName.IndexOf("/") != -1)
{
filePath += tempFileName.Substring(0, tempFileName.IndexOf("/") + 1);
tempFileName = tempFileName.Substring(tempFileName.IndexOf("/") + 1);
}
if (File.Exists(newFileName))
File.Delete(newFileName);

File.Copy(oldFileName, newFileName, true);
File.SetAttributes(newFileName, FileAttributes.Hidden);

status = "";
this.fileNameWithPath = newFileName;
//presentOperation = "Data Compressing";
//this.fileNameWithPath = ZipUnzip.LZO_Algorithm.LZO.Compress(this.fileNameWithPath);
//File.SetAttributes(filePath + this.fileNameWithPath, FileAttributes.Hidden);

if (this.fileNameWithPath.Length == 0)
return;

this.fileNameWithPath = filePath + tempFileName;// this.fileNameWithPath;
presentOperation = "Data Sending";
IPAddress[] serverIp = Dns.GetHostAddresses(SynchronusClient_ByteArr.ipAddress);
IPEndPoint ipEnd = new IPEndPoint(serverIp[0], SynchronusClient_ByteArr.portSend);
server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);

server.Connect(ipEnd);

int sentDataSize;
byte[] data;// = new byte[bufferSize];

bReader = new BinaryReader(File.Open(fileNameWithPath, FileMode.Open));
if (bReader.BaseStream.Length <= bufferSize) { data = new byte[bReader.BaseStream.Length]; bReader.Read(data, 0, (int)bReader.BaseStream.Length); sentDataSize = (int)bReader.BaseStream.Length; } else { data = new byte[bufferSize]; bReader.Read(data, 0, bufferSize); sentDataSize = bufferSize; } string onlyFileName; fileNameWithPath = fileNameWithPath.Replace("\\", "/"); onlyFileName = fileNameWithPath; while (onlyFileName.IndexOf("/") != -1) onlyFileName = onlyFileName.Substring(onlyFileName.IndexOf("/") + 1); //DATA FORMAT: [FILE SIZE LEN INFO[0-3]][FILE NAME LEN INFO[4-7]][FILE NAME DATA][FILE CONTENT] byte[] dataLenBytes = BitConverter.GetBytes((int)bReader.BaseStream.Length); byte[] fileNameLenBytes = BitConverter.GetBytes(onlyFileName.Length); byte[] fileNameBytes = Encoding.ASCII.GetBytes(onlyFileName); byte[] allData = new byte[8 + fileNameBytes.Length + data.Length]; //MAKE FIRST PACKET TO SERVER WITH FILE SIZE & FILE NAME dataLenBytes.CopyTo(allData, 0); fileNameLenBytes.CopyTo(allData, 4); fileNameBytes.CopyTo(allData, 8); data.CopyTo(allData, 8 + fileNameBytes.Length); //SEND FIRST PACKET TO SERVER server.Send(allData); totalSentDataSlot = 1; int totalDataSize = (int)bReader.BaseStream.Length; progress = (int)(((float)sentDataSize / totalDataSize) * 100); while (sentDataSize < progress =" (int)(((float)sentDataSize" enddata =" new" sentdatasize =" (int)bReader.BaseStream.Length;" progress =" (int)(((float)sentDataSize" receivedata =" new" recvlen =" server.Receive(receiveData);" presentoperation = "Data Sending Completed" status = "Access Denied by server end." status = "Address Already In Use." status = "Address Not Available." status = "Connection aborted by server." status = "Connection refused by server." status = "Connection Reset." status = "Destination Address Required." status = "Disconnecting." status = "Target Host is Down." status = "Target Host Not Found." status = "Target Host Unreachable." status = "In Progress." status = "Interrupted." status = "Invalid Argument." status = "Network Down." status = "Network Reset." status = "Network Unreachable." status = "No Buffer Space Available." status = "No Data." status = "Not Connected." status = "Not Initialized." status = "Not Socket." status = "Operation Aborted." status = "Socket already Shutdown." status = "Too Many Open Sockets." status = "Too Many Open Sockets." status = "Have some unknown problem in Socket." status =" ex.Message;" fbd =" new" outpathuserselected =" fbd.SelectedPath;" startfilereceivethread =" new" outpathuserselected =" ReceivePath;" startfilereceivethread =" new" server =" null;" bwriter =" null;" rcvfilename = "" filename = "" status = "" onlyfilename =" onlyFileNameObj.ToString();" presentoperation = "Data Compressing" length ="=" clientid =" DateTime.Now.Ticks.ToString();" clientidlenbytes =" BitConverter.GetBytes(clientId.Length);" clientidbytes =" Encoding.ASCII.GetBytes(clientId);" filenamelenbytes =" BitConverter.GetBytes(onlyFileName.Length);" filenamebytes =" Encoding.ASCII.GetBytes(onlyFileName);" alldata =" new" presentoperation = "Data Sending" serverip =" Dns.GetHostAddresses(SynchronusClient_ByteArr.ipAddress);" ipend =" new" server =" new" status = "" progress =" 0;" presentoperation = "" server =" (Socket)clientObject;" flag =" true;" data =" new" presentoperation = "Data Receiving" len =" server.Receive(data);" len ="=" strtemp =" Encoding.ASCII.GetString(data," strtemp ="=" status = "File yet not sent by Sender" presentoperation = "Data Receiving Not Started" progress =" 0;" totaldatalen =" BitConverter.ToInt32(data," filenamelen =" BitConverter.ToInt32(data," filename =" Encoding.ASCII.GetString(data," filecontentstartindex =" 4" receivedlen =" len;//" outpathdefault =" outPathDefault.Replace(" outpathuserselected =" outPathUserSelected.Replace(" fbd =" new" bwriter =" new" bwriter =" new" bwriter =" new" progress =" (int)(((float)receivedLen" len =" server.Receive(data);" val =" (float)receivedLen" progress =" (int)(((float)receivedLen" presentoperation = "Data Decompressing" rcvfilename =" ZipUnzip.LZO_Algorithm.LZO.Decompress(outPathDefault" rcvfilename =" ZipUnzip.LZO_Algorithm.LZO.Decompress(outPathUserSelected" orgfilename =" rcvFileName=" orgfilename =" orgFileName.Substring(orgFileName.IndexOf(" isserverrunning =" false;" presentoperation = "Data Receiving Completed" progress =" 100;" status = "Access Denied by server end." status = "Address Already In Use." status = "Address Not Available." status = "Connection aborted by server." status = "Connection refused by server." status = "Connection Reset." status = "Destination Address Required." status = "Disconnecting." status = "Target Host is Down." status = "Target Host Not Found." status = "Target Host Unreachable." status = "In Progress." status = "Interrupted." status = "Invalid Argument." status = "Network Down." status = "Network Reset." status = "Network Unreachable." status = "No Buffer Space Available." status = "No Data." status = "Not Connected." status = "Not Initialized." status = "Not Socket." status = "Operation Aborted." status = "Socket already Shutdown." status = "Too Many Open Sockets." status = "Too Many Open Sockets." status = "Have some unknown problem in Socket." status =" ex.Message;" style="">

Friday, October 23, 2009

Client to Client file transfer using C# .Net Programming - Remoting technology

For basic information regarding .Net Remoting technology you may refer my previous article “Global Text Chat Room Application Using C#.NET Remoting Technology”.

User manual:



To run that application first you have to run server application. Then you will get one winforms with two buttons ‘Start’ and ‘Stop’ as screenshot. Your have to run server by pressing Start button.

Now run client application. Here you will get first a winform which will ask your name and server address, port etc. If you try with same machine then the given address is ok. But if it different address then need to update ‘localhost’ with particular IP address or host name. But do not change port number and remaining thing and press enter or join button. See screenshot.

Then you will get another form. Here you will see online users in a TreeView. From here you need to select a user by double clicking on his/her name, and then need to select a file by pressing ‘Select a File’ button. A file dialog box window will come from where you need to select a file. Then press Send button. On receiver end one popup will come which will ask receiver will he receive it reject. If select receive then will ask a path where it will save. Then the file will transfer from sender to receiver.





Application logic:

For file transfer I have used basic codes of my previous project. Here also has three part –

(1) Base Remote Class (DLL)

(2) Server Class and

(3) Client Class

Server and Client class is using Base Remote Class.

In Base Remote Class have three sections (region) –

  1. Join to server and user related information
  2. File related information – file name, size, sender name, receiver name etc. and
  3. File transferring between two users.

For online user list I have used ArrayList object and for transferring data have used queue by HashTable.

In Server Class nothing very special. Here have just two methods, for starting server and stopping server. Start server is opening a TCPChannel and registering it, on the other side Stop Server is closing TCPChannel and unregistering it.

For login to server it exactly same as my previous article “Global Text Chat Room Application Using C#.NET Remoting Technology”.

In Client Class, there have few interesting parts. The major is a timer event. By this event client is checking to server if any data/information is available to it or not. Also by that timer collects latest user related information from server.

When client wants to send a file to some one then first it reads file related information and sends it to server with receiver id through SetFileInfo method of RemoteObject. Then it reads the file by a BinaryReader part by part and sends each part to server. In Server side it stores in a Hashtable from which receiver will receives it and server will remove each part one by as and when receiver confirms to remove after receivers’ acceptance. Here major roles plays SendFile method and Timer tick of Client and SendDataToServer, GetDataFromServer method of remote object class.

Basic architecture of my application is that, remaining of all you can understand if you go though the codes.

Remoting / Common base code is here:

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

using System.Collections;


namespace RemoteBase

{

///

/// Sample object to demonstrate the use of .NET Remoting.

///

public class SampleObject : MarshalByRefObject

{

ArrayList alOnlineUser = new ArrayList();

Hashtable htUserData = new Hashtable();

Hashtable htFileData = new Hashtable();

private int key = 0;

private string receiverID,senderID,fileName,fileTransferStatus;

private int fileSize;

private bool isFileTransferring = false;


#region USER JOINING AND ONLINE USER RELATED

public bool JoinToChatRoom(string name)

{

if (alOnlineUser.IndexOf(name) > -1)

return false;

else

{

alOnlineUser.Add(name);

return true;

}

}

public void LeaveChatRoom(string name)

{

alOnlineUser.Remove(name);

}

public ArrayList GetOnlineUser()

{

return alOnlineUser;

}

public int CurrentKeyNo()

{

return key;

}

#endregion


#region FILE INFORMATION ACCESS BETWEEN SENDER AND RECEIVER

public bool SetFileInfo(string senderId, string receiverId, string fileName, int fileSize)

{

if (!this.isFileTransferring)

{

lock (this)

{

this.isFileTransferring = true;

}

this.senderID = senderId;

this.receiverID = receiverId;

this.fileName = fileName;

this.fileSize = fileSize;

return true;

}

else//Now some file transferring, so need to wait

return false;

}

public string GetFileName_Size_SenderId(string receiverId)

{

if (this.receiverID == receiverId)

return this.fileName + ":" + this.fileSize.ToString() + ":" + this.senderID;

else

return null;

}

#endregion



#region FILE TRANSFER BETWEEN SENDER AND RECEIVER


///

/// This method is used to receive data from sender and hold in a array to deliver receiver.

///

///

///

///

///

public bool SendDataToServer(byte[] data, int dataSliceNo, string senderId)

{

lock (this)

{

htFileData.Add(receiverID + dataSliceNo.ToString(), data);//Key= receiverId + sliceNo, binary data

}

return true;

}

// This method is used to receive data from server to receiver.

public byte[] GetDataFromServer(string receiverId, int nextSliceNo)

{

if (htFileData.Contains(receiverID + nextSliceNo.ToString()))

{

lock (this)

{

byte[] tempByteData = (byte[])htFileData[receiverID + nextSliceNo.ToString()];

htFileData.Remove(receiverID + nextSliceNo.ToString());//Key= receiverId + sliceNo

return tempByteData;

}

}

else

return null;

}


///

/// This method is used to declare that file has succesfully received by the receiver. It invokes after the whole file

/// received by the receiver.

///

///

public void ReceiveFileConfirm(string clientID)

{

if (clientID == receiverID)

{

this.fileTransferStatus = "File transfered successfully by " + this.receiverID;

this.receiverID = "";

lock (this)

{

this.isFileTransferring = false;

htFileData.Clear();

}

}

}

public void RejectFile(string clientID)

{

if (this.receiverID == clientID)

{

this.fileTransferStatus = "File has rejected by " + this.receiverID;

this.receiverID = "";

lock (this)

{

this.isFileTransferring = false;

htFileData.Clear();

}

}

}

#endregion

}

}


Server code is here:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

using RemoteBase;

namespace RemoteServer

{

public partial class Form1 : Form

{

public Form1()

{

InitializeComponent();

}

TcpChannel channel;

private void btnStart_Click(object sender, EventArgs e)

{

if (channel == null)

{

channel = new TcpChannel(8080);

ChannelServices.RegisterChannel(channel, false);

RemotingConfiguration.RegisterWellKnownServiceType(typeof(SampleObject), "HelloWorld", WellKnownObjectMode.Singleton);


lblStatus.Text = "Running...";

btnStart.Enabled = false;

btnStop.Enabled = true;

}

}


private void btnStop_Click(object sender, EventArgs e)

{

if (channel != null)

{

ChannelServices.UnregisterChannel(channel);

channel = null;

lblStatus.Text = "Stopped.";

btnStart.Enabled = true;

btnStop.Enabled = false;

}

}


}

}


Client code is here:

Login and server connecting code:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

using System.Collections;

using RemoteBase;

namespace RemotingClient

{

public partial class frmLogin : Form

{

TcpChannel chan;

ArrayList alOnlineUser = new ArrayList();

frmChatWin objChatWin;

public frmLogin()

{

InitializeComponent();

}


private void btnJoin_Click(object sender, EventArgs e)

{

JoinToChatRoom();

}

private void JoinToChatRoom()

{

if (chan == null && txtName.Text.Trim().Length != 0)

{

chan = new TcpChannel();

ChannelServices.RegisterChannel(chan,false);


// Create an instance of the remote object

objChatWin = new frmChatWin();

objChatWin.remoteObj = (SampleObject)Activator.GetObject(typeof(RemoteBase.SampleObject), txtServerAdd.Text);


if (!objChatWin.remoteObj.JoinToChatRoom(txtName.Text))

{

MessageBox.Show(txtName.Text+ " already joined, please try with different name");

ChannelServices.UnregisterChannel(chan);

chan = null;

objChatWin.Dispose();

return;

}

objChatWin.key = objChatWin.remoteObj.CurrentKeyNo();

objChatWin.myName= txtName.Text;


this.Hide();

objChatWin.Show();

}

}

}

}

File transferring code:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

using System.Collections;

using RemoteBase;

using System.IO;

using System.Threading;

namespace RemotingClient

{

public partial class frmChatWin : Form

{

internal SampleObject remoteObj;

internal int key = 0,fileSize;

int sliceSize = 5 * 1024;

internal string myName,fileName;

ArrayList alOnlineUser = new ArrayList();

string selectedUserName;

OpenFileDialog ofd;

public frmChatWin()

{

InitializeComponent();

}


private void btnSend_Click(object sender, EventArgs e)

{

SendFile();

}

private void timer1_Tick(object sender, EventArgs e)

{

timer1.Stop();

if (remoteObj != null)

{

string receiveFileName, senderId;

int fileSize;

string FileName_Size = remoteObj.GetFileName_Size_SenderId(myName);

if (FileName_Size != null)

{


string[] recvFileDesc = FileName_Size.Split(':');

receiveFileName = recvFileDesc[0];

fileSize = int.Parse(recvFileDesc[1]);

senderId = recvFileDesc[2];


DialogResult usrRes = MessageBox.Show(senderId + " want to send a file. Will you accept it?", "", MessageBoxButtons.YesNo);

if (usrRes == DialogResult.Yes)

{

FolderBrowserDialog fbdSelect = new FolderBrowserDialog();

fbdSelect.Description = "Select a path to save received file.";

if (fbdSelect.ShowDialog() == DialogResult.OK)

{

BinaryWriter bWrite = new BinaryWriter(new FileStream(fbdSelect.SelectedPath+"\\" + receiveFileName, FileMode.Append));

for (int i = 0; i * sliceSize <= fileSize; )

{

byte[] buffer = remoteObj.GetDataFromServer(myName, i + 1);//i+1 because when data send to server the it starts from 1

if (buffer != null)

{

bWrite.Write(buffer);

i++;

}

}

bWrite.Close();

remoteObj.ReceiveFileConfirm(myName);

MessageBox.Show("File received successfully.");

}

}

else

{

remoteObj.RejectFile(myName);

}

}

ArrayList onlineUser = remoteObj.GetOnlineUser();

foreach (string name in onlineUser)

{

if (name != myName && !tvOnlineUser.Nodes.ContainsKey(name))

tvOnlineUser.Nodes.Add(name, name);

}

}

//**** Button Enable - Disable

if (tvOnlineUser.Nodes.Count > 0 && lblSelUser.Text.Length > 15)

btnSelect.Enabled = true;

else

btnSelect.Enabled = false;

btnSend.Enabled = false;

if (ofd != null)

if (ofd.FileName.Length > 0)

btnSend.Enabled = true;

timer1.Start();

}

private void SendFile()

{

if (remoteObj != null)

{

BinaryReader bRead = new BinaryReader(new FileStream(ofd.FileName, FileMode.Open));

fileSize = (int)bRead.BaseStream.Length;

if (fileSize > 1024 * 1024 * 50)

MessageBox.Show("You can send maximum 50 MB file.", "Limit cross!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);

else

{


byte[] smallPiece;


if (fileSize <>

{

smallPiece = new byte[fileSize];

bRead.Read(smallPiece, 0, fileSize);

}

else//File is more than 5KB

{

smallPiece = new byte[sliceSize];

if (remoteObj.SetFileInfo(myName, selectedUserName, fileName, fileSize))

{

for (int i = 1; i * sliceSize <= fileSize + sliceSize; )

{

if (i * sliceSize <= fileSize) // Last slice yet not reached

{

bRead.Read(smallPiece, 0, sliceSize);

if (remoteObj.SendDataToServer(smallPiece, i, myName))

i++;

}

else//Last slice of data is going to fetch and for last slice data remains less than 5KB

{

int remainDataSize = fileSize - ((i - 1) * sliceSize);

smallPiece = new byte[remainDataSize];

bRead.Read(smallPiece, 0, remainDataSize);

if (remoteObj.SendDataToServer(smallPiece, i, myName))

i++;

}

}

}//End of SetFileInfo

}

}

bRead.Close();

}

}

private void Form1_FormClosed(object sender, FormClosedEventArgs e)

{

if (remoteObj != null)

{

remoteObj.LeaveChatRoom(myName);

}

Application.Exit();

}


private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)

{

System.Diagnostics.Process.Start("iexplore.exe", "http://socketprogramming.blogspot.com");

}

private void btnSelect_Click(object sender, EventArgs e)

{

ofd = new OpenFileDialog();

if (ofd.ShowDialog() == DialogResult.OK)

{

lblSelectedFile.Text = "Selected File: "+ofd.SafeFileName;

fileName = ofd.SafeFileName;

}

}


private void tvOnlineUser_DoubleClick(object sender, EventArgs e)

{

selectedUserName = tvOnlineUser.SelectedNode.Name;

lblSelUser.Text = "Selected User: "+selectedUserName;

}

}

}