PDA

Click to See Complete Forum and Search --> : VB.Net client/server file transfer


Disyne
Sep 2nd, 2009, 01:16 AM
Hi I am using this as an guideline for my client/server: http://www.vbforums.com/showthread.php?t=502795

I was wondering if there is an example on how to do a file transfer client to server and back?

I did a few searches but couldn't find anything, could be my search tags weren't exact enough.:(

chris128
Sep 2nd, 2009, 05:03 AM
I've never tried it but I think as you are already just sending and receiving Bytes using that method that is in that thread you linked to then all you would need to do is get the Byte representation of the file and just send that in the same way as anything else.
So for example you could open a FileStream to the file you want to send and then just call the Read or ReadByte method on the FileStream to fill up a Byte array with the data from the file, then send that Byte array in the same way you would send any other message.

Disyne
Sep 2nd, 2009, 02:07 PM
Thanks for the help.

Wondering if the File.ReadAllBytes() would work just as well?

The way I am sending info to the server is sending some kind of identifier to tell what kind of message it is. Like "m|abc123" Would mean the client sent a chat message of abc123. How would I incorporate that into sending the file? Like.."f|bytes"
That way the server would know everything after f| is part of a file?

chris128
Sep 2nd, 2009, 02:09 PM
yeah ReadAllBytes is probably a lot easier :) totally forgot that existed...
and yeah thats how I would do it, just use an identifier at the start of each message, so your receiving server would split the string on the first instance of the | character and then process the message based on the characters found before that.

Disyne
Sep 2nd, 2009, 02:13 PM
I am unsure on how to add the string to the byte array.
I have my readallbytes into the byte array, but how would I add say "f|" at the very beginning converting the string to byte format?

chris128
Sep 2nd, 2009, 02:33 PM
You can convert a string to bytes using System.Text.Encoding.ASCII.GetBytes (or something like that)

Disyne
Sep 2nd, 2009, 05:18 PM
Hm, I send the bytes and everything, but when I display the info the server is receiving it is always shown as: "System.Byte[]"

I have tried the encoding getstring but it just displays System.Byte[] always. Any ideas on what I am doing wrong?

chris128
Sep 2nd, 2009, 05:24 PM
Are you sure you are using GetString correctly? Its a function so it will return the resulting string, not convert the original byte array (but I'm guessing you already know that). Can you post the relevant parts of your code here for us to take a look at?

Disyne
Sep 2nd, 2009, 05:37 PM
I am most likely not understanding on how to use something properly, here's exactly what I am doing:

Client side I am sending a simple text file that says test 101 inside of it.


Dim b As Byte() = File.ReadAllBytes(txtFile.Text)
sw.Write("f|")
sw.Write(b)
sw.Write("|" & EndChr & ControlChars.Cr)
sw.Flush()

Server side I get the data and do this just for testing:
Dim message As String = System.Text.Encoding.UTF8.GetString(readBuffer, 0, bytesRead)
MsgBox(message)
It says "f|System.Byte[]|~:
The beginning and end of it is good just the system.byte[] I need to figure out what to do with it.
Now if I dont send the f| and everything, just the byte array itself and when I receive it server side and do a file.writeallbytes it will write System.Byte[] to the file and not the actual data.

Do I have to do some kind of conversion or something to the data that is displaying System.Byte[]? I'm doing something wrong or missing something, but unsure of what that is.

chris128
Sep 2nd, 2009, 05:53 PM
I'm assuming your "sw" object is of type StreamWriter? Change it to type NetworkStream (use the TcpClient.GetStream method to return a NetworkStream for the current connection) and then you can use the WriteByte method :)

Disyne
Sep 4th, 2009, 01:27 AM
Ok, I have got everything working and updated.

Right now I am just using File.ReadAllBytes and sending it all instantly with a BinaryWriter.

How would I go about determining the speed of the upload and how much is currently uploaded? Basically..a progress bar telling me how far along the upload is (if it is a larger file).

Atheist
Sep 4th, 2009, 01:43 AM
Ok, I have got everything working and updated.

Right now I am just using File.ReadAllBytes and sending it all instantly with a BinaryWriter.

How would I go about determining the speed of the upload and how much is currently uploaded? Basically..a progress bar telling me how far along the upload is (if it is a larger file).

In order for you to do this, I believe you must do something that I still think you should, and that is read and send portions of the file continuously.
Create a buffer (array of bytes) of say 8192 bytes.
Open a FileStream to the file you are intending to send, and then just do the following until you reach the end of the FileStream:

1. Fill the buffer up as much as possible with data from the FileStream, possibly using its Read method. Note that the Read method also returns an integer telling you exactly how much bytes where actually read. It is not always so that the buffer will be completely filled.

2. Write the bytes that was placed in the buffer, to the NetworkStream, using the BinaryWriter.

3. Keep track of how much you've sent so far. Report progress if you'd like. Though it may be too frequent to report progress for each 8192 bytes sent, so you might want to consider making the buffer larger, or just keeping track so that you are not reporting progress every iteration.


The reason I think you should've done something like this in the first place is that in case of really large files, you would'nt be hogging up memory by reading it all into a byte array, then sending it.

Disyne
Sep 4th, 2009, 02:27 PM
I have made a new class for the client side called FileUpload:
Imports System.IO
Public Class FileUpload
Public PB As ProgressBar
Public FilePath As String
Public FileName As String
Private fs As FileStream
Private BYTES_TO_READ As Integer = 10000
Private buffer(BYTES_TO_READ) As Byte
Private totalRead As Integer = 0

Public Sub FileUpload()
fs = New FileStream(FilePath, FileMode.Open)
If fs.CanRead Then
SendServer("UPLO", FileName, fs.Length)
Do Until totalRead = fs.Length
totalRead += fs.Read(buffer, 0, BYTES_TO_READ)
SendRaw(buffer)
ProgressSet(totalRead / fs.Length * 100)
Loop
End If
fs.Close()
End Sub

Public Delegate Sub ProgressSetInvoker(ByVal value As Integer)
Public Sub ProgressSet(ByVal value As Integer)
If PB.InvokeRequired Then
PB.Invoke(New ProgressSetInvoker(AddressOf ProgressSet), value)
Else
PB.Value = value
End If
End Sub
End Class
It (visually) seems to be working.

Now server side, it is receiving my identifier command "UPLO" and the name and size of the file being sent. I then order the server to ReadBytes the amount of the filesize.

d is the filename.
d2 is the filesize in bytes.

It is not not going past bw.ReadBytes(d2)
I am unsure what I am doing wrong.

Case "UPLO"
d = bw.ReadString()
d2 = bw.ReadInt32()
Dim bdata() As Byte = bw.ReadBytes(d2)
File.WriteAllBytes(UsersDir & Username & "\" & d, bdata)


Here are the SendRaw and SendServer subs:
Public Sub SendServer(ByVal command As String, ByVal ParamArray data() As String)
Dim bw As IO.BinaryWriter
Dim b As Byte() = System.Text.Encoding.UTF8.GetBytes(command)
Try
SyncLock client.GetStream
bw = New IO.BinaryWriter(client.GetStream)
bw.Write(b)
For i As Integer = 0 To UBound(data)
bw.Write(data(i))
Next
bw.Flush()
End SyncLock
Catch ex As Exception
MessageBox.Show(ex.ToString)
End Try
End Sub

Public Sub SendRaw(ByVal data() As Byte)
Dim bw As IO.BinaryWriter
Try
SyncLock client.GetStream
bw = New IO.BinaryWriter(client.GetStream)
bw.Write(data)
bw.Flush()
End SyncLock
Catch ex As Exception
MessageBox.Show(ex.ToString)
End Try
End Sub

Disyne
Sep 5th, 2009, 01:21 PM
I have had some progress it seems.

This is the server side part that handles the upload from the client:

d = filename
d2 = file size in bytes

d = bw.ReadString()
d2 = bw.ReadString()
Dim read As Integer = 0
Dim totalRead As Integer = 0
Dim bdata(10000) As Byte
Dim fs As FileStream = File.Create(UsersDir & Username & "\" & d)
Do Until totalRead = d2
read = Me.mClient.GetStream.Read(bdata, 0, 10000)
totalRead += read
fs.Write(bdata, 0, read)
Loop

This is the client side part that handles the upload:
Public Sub FileUpload()
fs = New FileStream(FilePath, FileMode.Open)
If fs.CanRead Then
SendServer("UPLO", FileName, fs.Length.ToString)
Do Until totalRead = fs.Length
read = fs.Read(buffer, 0, BYTES_TO_READ)
totalRead += read
ReDim sendBuffer(read - 1)
Array.Copy(buffer, sendBuffer, read - 1)
SendRaw(sendBuffer)
ProgressSet(totalRead / fs.Length * 100)
Loop
End If
fs.Close()
End Sub
The server receives the total amount of bytes that it should, but say if I upload an image. The server will receive it and make the file and the size will be the same on the client side, but the image will be partially correct other parts will be discolored or distorted.

Now if I sent a .txt file the server will receive all the text inside of it, but the last character will be replaced with a space.

So say I sent a .txt file with the following inside : "test 123"
The server would write to the .txt "test 12 "
Always a space as the last character.

Disyne
Sep 8th, 2009, 05:27 PM
bump