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;

}

}

}


18 comments:

Kumar Vivek said...

dear sir
i m makin online test and thr i need to copy some files from server to client(some 500kb) and then at test completion i want to delete those files from thr and want a single file(50kb) back on server from client.
how can i do tht?I m in serious trouble.plz help me.
if possible i dont want client 2 know that i m copying some files on its system

Kumar Vivek said...

no sir
this is not what i wanted
mine requirement is that
i want 2 copy some data n files on client system before start of test and after test completion we want a few files back from that client to our server this is my requirement
plz help.....how can i copy files on my client system without actually acknowledging him

Suman Biswas said...

Hi,
You can not write any file to client's system without his permission from browser.

If it is not answer of your question then you may not express clearly about what you need.

Thanks,
Suman

Kumar Vivek said...

no no this is wat i wanted....
now... how can I copy files on client's system after getting his permission...can i have code(c#.net) or explanation of tht plz.......

Suman Biswas said...

Server to Client file transfer by server action ... it is not possible. If client request server to send some data then server can do it, otherwise server can not send data.

So far I know from server to client data transfer is possible in .Net 3.5 in WCF technology. But I do not have experience with that.

Suman

UkraineTrain said...

Hi Suman,

Sorry to bother you over a topic unrelated to this post, but I've been reading your post for a "Large File (2 GB) Transfer using C# Socket" and could not download the source code, because the links provided there are dead. Can you, please, post valid links. I really appreciate it in advance.

Suman Biswas said...

Hi UkraineTrain,
Thanks for pointing that error in that link (2GB file transfer using socket).
I have updated the link. Now you may try to download.

Thanks again,
Suman

liza said...

hi
this code is for only transfering in server and client. can u give an idea for the peer to peer.

liza said...

u can send me code in my mail address if u have it and for hash table too

Kalyani said...

I cant download file tranfer code for 4GB.I thnk there is problem with link

Cedric said...

Hi, I would like to know what does the following line in the Client Class:

"if (fileSize <>"


I really apreciate if someone could help.
I'm doing a similar project for school.

Cedric said...

Hi, I would like to know what does the following line in the Client Class:

"if (fileSize <>"


I really apreciate if someone could help.
I'm doing a similar project for school.

Krishna said...

it's very nice. Thank's for sharing.
Is there any way to register with two server. I mean if one server reject the channel registration then how can i transfer request to another server with differnt port.

Suman Biswas said...

Hi Krishna,
This can possible. To do it try to apply your own programming concept. Because now you know basic thing about socket programming.
:-) thanks for your reply.

Thanks,
Suman

Unknown said...

thanks for the post because i was looking for this C# development related solutions...

avaneesh said...

hi suman sir;
please provide me a valid linq to download the full project of transfer the large file(2GB) using c#.net.I will be very thankfull to you i need a lot that linq
please provide as soon as possible i am waiting....

Unknown said...

Hello, thanks for you sharing. I wanna ask a question. Hope you can answer.

Do i need an temp sever to chat with my friend who is far from me (not in LAN network) using this code? If can, how can i do that? How can my friend's computer makes a connection with my computer (not in LAN network)?

scott overy said...

I want to thank you for this good read!! I certainly loved every little bit of it. I have got you saved as a favorite to look at new stuff you post…
Domain Age Checker