|
-
Dec 11th, 2011, 01:16 PM
#1
Thread Starter
Hyperactive Member
Transfer file over network
I have tried to find a way to transfer files, big or small, over the network via either tcp/ip or sockets or whatever it is called (I am new in this area).
But I don't feel any of the tutorials I have found are good. Either the code is hard to understand or there a limits on things like the size of the file (?).
I would appreciate if anyone would redirect me in the right direction, maybe a good tutorial or explanation
-
Dec 12th, 2011, 03:48 AM
#2
Re: Transfer file over network
Do you need both the client and server ends?
-
Dec 12th, 2011, 02:16 PM
#3
Thread Starter
Hyperactive Member
Re: Transfer file over network
Yeah, I have nothing so far (just code to write and read from a networkstream, for a chat).
-
Dec 15th, 2011, 06:27 PM
#4
PowerPoster
Re: Transfer file over network
same principals. the only difference is on how your logic is.
it would help if you posted the code you currently have. without it... we cant really help.
Again - MSDN has great resources and examples. you just need to tailor to your needs.
its just a matter of establishing a connection then transmitting the file from the sender in say, chunks, and for the receive to keep reading the stream until there is no more data to be left, then close the file you are writing to or signal an EOF from the sender so the receiver knows when to effectively stop writing data and close off the file
-
Dec 16th, 2011, 12:52 PM
#5
Thread Starter
Hyperactive Member
Re: Transfer file over network
Here is the code for sending a message:
Code:
public static void SendMessage(string Message, string To)
{
StreamWriter swSenderSender;
int count;
TcpClient[] tcpClients;
if (To == "@All")
{
// Create an array of TCP clients, the size of the number of users we have
tcpClients = new TcpClient[ChatServer.htUsers.Count];
// Copy the TcpClient objects into the array
ChatServer.htUsers.Values.CopyTo(tcpClients, 0);
count = tcpClients.Length;
}
else
{
tcpClients = new TcpClient[1];
tcpClients[0] = (TcpClient)htUsers[To];
count = 1;
}
// Loop through the list of TCP clients
for (int i = 0; i < count; i++)
{
// Try sending a message to each
try
{
// If the message is blank or the connection is null, break out
if (Message.Trim() == "" || tcpClients[i] == null)
{
continue;
}
// Send the message to the current user in the loop
swSenderSender = new StreamWriter(tcpClients[i].GetStream());
swSenderSender.WriteLine(Message);
swSenderSender.Flush();
swSenderSender = null;
}
catch // If there was a problem, the user is not there anymore, remove him
{
RemoveUser(tcpClients[i]);
}
}
}
I didn't write it all by myself, but I have done modifications to the original. And I also think that I have somewhat understood how it works.
Here is the code for receiving:
Code:
try
{
// Keep waiting for a message from the user
while ((strResponse = srReceiver.ReadLine()) != "")
{
// If it's invalid, remove the user
if (strResponse == null)
{
ChatServer.RemoveUser(tcpClient);
}
else
{
//Send data about the user who said it, and what it said
e = new StatusChangedEventArgs(currUser, strResponse);
ChatServer.OnStatusChanged(e);
}
}
}
So the two programs share a stream, and when something is written to it, the "other part"/client/server sees it.
Though I have a question about the writing:
If I write for example the string "Hello" to the stream, is it written all at once or a little bit at a time (like when you are handwriting it to a paper)?
Since this code works, it must be written all at the same time, though that doesn't seem logical 
Anyway, so yeah if I were to write the bytes to that stream and some strings that tells the server that it is a file I am sending and where it ends, would that work?
And about the chunk-thingy that you wrote about, how does that work?
-
Dec 17th, 2011, 07:10 AM
#6
Thread Starter
Hyperactive Member
Re: Transfer file over network
I read more about this subject yesterday and think I understand it better now.
I just wrote up a few lines to test a transfer:
Code:
private static void SendFile()
{
NetworkStream stream = tcpServer.GetStream();
byte[] fileData = File.ReadAllBytes("C:\test.txt");
stream.Write(fileData, 0, fileData.Length);
}
I think that is the bare minimum of code needed to send a file (probably should do some ending too, + add filename into the byte array).
But I then got stuck on the receiving part.
As I showed you before, this is the code for receiving a chatmessage:
Code:
// Keep waiting for a message from the user
while ((strResponse = srReceiver.ReadLine()) != "")
{
// If it's invalid, remove the user
if (strResponse == null)
{
ChatServer.RemoveUser(tcpClient);
}
else
{
//Send data about the user who said it, and what it said
e = new StatusChangedEventArgs(currUser, strResponse);
ChatServer.OnStatusChanged(e);
}
}
Though it reads everything like a string from the stream. So I figured I needed to use the tcpServer.GetStream() here too.
So this is the rough code I came up with:
Code:
NetworkStream stream = tcpClient.GetStream();
byte[] fileData = new byte[30000];
while ((stream.Read(fileData, 0, fileData.Length)) > 0)
{
string test = System.Text.UTF8Encoding.ASCII.GetString(fileData);
}
And it works :>
Though as you can see I am setting a pre-defined size on the byte array, because I don't know how to get the size of the data on the stream.
So yeah, I guess I have to read a little more to get to know that unless someone can hint me about it
-
Dec 17th, 2011, 08:10 AM
#7
Re: Transfer file over network
Are you only going to be sending only text files? If not then why are you reading the data at text at the receiving end? If your aim is to upload a file then I would think that the logical thing to do would be to read the raw binary data and write that data to a file. There's also no reason that you have to read all the data in one go. In fact, there's no way you can if you don't know how big the file is when you start reading. So, how could you know at the receiving end what size the file is? Do you know at the sending end? If so, why can't you send that information first?
-
Dec 17th, 2011, 08:45 PM
#8
Thread Starter
Hyperactive Member
Re: Transfer file over network
Haha yeah I realised that when I had finished writing it, though I thought "What the hell, I'll know what is wrong, I'll fix it later".
One interested thing I stumbled upon was the property NetworkStream.Length Which should return the length of the data on the stream, though it said "not implemented" lol :P
Anyway, hmm okay send the length of the file. I'll write something up and show you tomorrow :>
Just a quick question, if I convert the length of a file to a byte array, how big does the file need to be for it's length(converted to byte array) to not fit into a for example byte[4]? (Hint: yes I have started working on the code)
-
Dec 17th, 2011, 10:42 PM
#9
Re: Transfer file over network
Given that the FileInfo.Length property is type Int64, it would make sense to transmit the file size as a 64-bit number. You might look at using a BinaryWriter and BinaryReader, which will allow you to write/read both the number and the data directly, or else look at the BitConverter class for converting between numbers and byte arrays.
-
Dec 17th, 2011, 10:45 PM
#10
Re: Transfer file over network
 Originally Posted by Cyb3rH4Xter
One interested thing I stumbled upon was the property NetworkStream.Length Which should return the length of the data on the stream, though it said "not implemented" lol :P
It should, should it? Did you actually read the documentation for that property? How do you suppose the Length property value is produced? All the bytes in the Stream would have to be counted, would they not? How can a NetworkStream count the bytes when they are on the other side of a network connection? If you cannot Seek randomly through a Stream then you cannot get its Length either.
-
Dec 19th, 2011, 06:12 PM
#11
Thread Starter
Hyperactive Member
Re: Transfer file over network
 Originally Posted by jmcilhinney
Given that the FileInfo.Length property is type Int64, it would make sense to transmit the file size as a 64-bit number. You might look at using a BinaryWriter and BinaryReader, which will allow you to write/read both the number and the data directly, or else look at the BitConverter class for converting between numbers and byte arrays.
Yeah I have used the BitConverter. I used the byte[].Length to get the length of the file and then converted that int to byte[] with the BitConverter.
 Originally Posted by jmcilhinney
It should, should it? Did you actually read the documentation for that property? How do you suppose the Length property value is produced? All the bytes in the Stream would have to be counted, would they not? How can a NetworkStream count the bytes when they are on the other side of a network connection? If you cannot Seek randomly through a Stream then you cannot get its Length either.
Oh I see. Well I recently discovered the Seek method and wanted to use it, but yeah it doesn't work either.
I have written some code, though I am stuck in one (maybe more) place and probably need to rewrite something hehe.
Here is the new send part:
Code:
NetworkStream stream = tcpServer.GetStream();
byte[] fileData = File.ReadAllBytes("C:\\test.zip");
int length = fileData.Length;
byte[] fileLength = BitConverter.GetBytes(fileData.Length);
byte[] protocolID = BitConverter.GetBytes(1337);
byte[] sendData = new byte[8 + fileData.Length];
protocolID.CopyTo(sendData, 0);
fileLength.CopyTo(sendData, 4);
fileData.CopyTo(sendData, 8);
stream.Write(sendData, 0, sendData.Length);
Which I think looks quite nice (of course I will make it more "safe" when I am done).
But when it comes to the reading part, I feel I have lost the control a bit:
Code:
NetworkStream stream = tcpClient.GetStream();
while (true) //Is there something better to replace true with? stream.DataAvailable won't work since it jumps out of the loop as soon as there is no data available.
{
byte[] info = new byte[8];
if (stream.Read(info, 0, 8) <= 0)
{
//Fail
}
int protocol = BitConverter.ToInt32(info, 0);
if (protocol != 1337)
{
//don't care about other protocols for now
continue;
}
int size = BitConverter.ToInt32(info, 4);
byte[] fileData = new byte[size];
if (stream.Read(fileData, 0, fileData.Length + 8) <= 0)
{
//Fail
}
File.WriteAllBytes("C:\\testTransf.zip", fileData.); //Here is the problem kinda, I only want to write the later part of the fileData (start from 8) but I have no idea how.
}
Also, the code doesn't seem that optimal, it feel quite dirty
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|