I have created a program that uses tcp/ip sockets to communicate between the client and server. I am looking for a way to send a file to the server over this connection that already exists. I understand that a network stream will have to be used. I found this code on another post written by Atheist, that will send the contents of the file through the network stream. I think that will work.
Code:
Dim sendBuffer(1023) As Byte
Dim fileToSend As String = "c:\somePicture.jpg"
Dim fStream As System.IO.FileStream
Dim bytesRead As Integer = 0
If System.IO.File.Exists(fileToSend) Then
fStream = New System.IO.FileStream(fileToSend, IO.FileMode.Open)
Do
bytesRead = fStream.Read(sendBuffer, 0, 1024)
If bytesRead > 0 Then
nStream.Write(sendBuffer, 0, bytesRead) 'Where nStream is the NetworkStream for the connection
End If
Loop While bytesRead > 0
End If
As for the part that im not sure of, is what do i have to do to recieve the file on the server side? Maybe somebody could supply come code for piecing the file back together. Another things that would be useful would be a list of procedure that needs to be followed to get the transfer to work. as of right now I have
Client:
1.get file path
2.read file into pieces
3.send each piece
Server:
4.read each piece
5. assemble back into a file
Does the receiving end know how large the file is in advance? Or to rephrase the question; What does the receiving end know about the file being transfered?
And also, will you be using this connection for other communication whilst this data is being sent?
The receiving(server) end will know nothing about the file in advance. This is for a robot project that I am working on. I need to be able to send the updated version of the control programs to it. There is a chance that it will be sending during other communication, I would like it to be able to do this but if it isnt possible, its not a major loss. -Adam
The receiving(server) end will know nothing about the file in advance. This is for a robot project that I am working on. I need to be able to send the updated version of the control programs to it. There is a chance that it will be sending during other communication, I would like it to be able to do this but if it isnt possible, its not a major loss. -Adam
Well, I really think you should open up a new connection for the filetransfer, then close it once it finishes. It will make things alot easier for you.
You could then, before the transfer starts, tell the receiving end how large the file is (on the main tcp connection), so it knows how many bytes it should expect.
I could try to throw together a class for you if you'd like, or would you rather try yourself?
So by creating a new connection I would still be able to control my robot and run query's, while sending the update files to it? Sounds good
It would be very handy if you did create the class file, because im not a programing expert. I'm an electronics engineering student. lol
In this class, would it be used in each project (Client and server) and access different parts of the class?
The other thing I was wondering about is creating it so that it can show a progress bar for the file being sent. I think that this would be easy, by just comparing the total size of the file to the amount sent.
Alright I've thrown together this, I wouldnt call it 100% complete (needs improved error handling), but does its job.
The way this works is; When host A wants to send a file to host B, host A creates an instance of the FileTransferSend class (and stores it in a collection of some sort, just to keep a reference to each transfer) and sends the following information to host B:
-The name of the file.
-The size of the file (in bytes)
-The port on which host B should connect to receive the file.
Once host B receives this information, it should create an instance of the FileTransferReceive class (and store it in a collection, as above), passes all the information it just received to the FileTransferReceive's constructor, along with the hosts address.
The FileTransferReceive class will automatically connect to the given address and portnumber, and upon doing so, host A will automatically begin sending the file.
That was a lousy explanation...well, if you just add these classes to your project(s), we can go through it step-by-step.
Here are the two classes:
VB.NET Code:
Public Class FileTransferReceive
Private m_client As System.Net.Sockets.Socket
Private m_file As String
Private m_fileLength As Long
Private m_thread As System.Threading.Thread
Private BUFFER_SIZE As Integer = 8192
Public Event TransferFinished(ByVal sender As FileTransferReceive, ByVal file As String)
Public Event TransferFailed(ByVal sender As FileTransferReceive, ByVal file As String)
Sub New(ByVal address As System.Net.IPAddress, ByVal port As Integer, ByVal file As String, ByVal length As Long)
m_file = file
m_fileLength = length
m_client = New System.Net.Sockets.Socket(Net.Sockets.AddressFamily.InterNetwork, Net.Sockets.SocketType.Stream, Net.Sockets.ProtocolType.Tcp)
m_client.Connect(address, port)
m_thread = New System.Threading.Thread(AddressOf doRead)
m_thread.IsBackground = True
m_thread.Start()
End Sub
Private Sub doRead()
Dim receiveBuffer(BUFFER_SIZE - 1) As Byte
Dim bytesRead As Integer = 0
Dim totalBytesRead As Long = 0
Dim fStream As System.IO.FileStream = Nothing
Dim failed As Boolean = False
Try
fStream = New System.IO.FileStream(System.IO.Path.Combine(Application.StartupPath, m_file), IO.FileMode.Create)
WOW. Thankyou. I created 2 new projects just to figure out everything and make sure it works before putting it in my robot program. The projects are called FileTransferSend and FileTransferRecieve. I added the code to the one it belongs in. It looks good, just not sure where I put the address of the file I want to send and and what I call to start the Process.Again thankyou.-Adam
Whenever you want to send a file you create a new FileTransferSend class instance, and pass the address to the file in the constructor:
VB.NET Code:
Dim transfer As New FileTransferSend("C:\somePicture.jpg")
Directly after creating this instance, you should send the information to the reciever: Filename, filesize, and port number (retrieve the portnumber from by using the GetPortNumber property from the FileTransferSend instance you just created)
This is so the receiver can create a FileTransferReceive class instance to receive your file.
... and what I call to start the Process.Again thankyou.-Adam
You can send as many files as you like, whenever you like. Just do the process all over again.
Oh I should also tell you;
You must add the classes to a collection of some sort after creating them, or else they'll be unreferenced and could be picked up for garbage collection. You also need to handle the TransferFailed/TransferFinished events in which you remove the instance that raised the event from the collection.
Im kinda confused. I can send the information about the file to the receiving end, but im not sure how I call the receive code with the information and start the receive process. Also, how dose it know where to save the file to? Thannk-you for your help. -Adam
Alright, when you receive the information about the file on the receiving end, create a FileTransferReceive instance and pass the information to the constructor. The first argument of the constructor is the IP-address of the client, so retreiving the ip address of the sender kinda depends on how your application is designed.
VB.NET Code:
Dim transfer As New FileTransferReceive(SomeIP, PortNumber, FileName, FileSize)
' Add it to a collection of some sort, and add the eventhandlers for TransferFinished and TransferFailed.
If you have the possibility to, posting your code would help me give you better examples of how you should go about doing this.
Here are the 2 projects that I created to set this up and get working. The code in it is the same as what I used in my actual program. I then added the code you wrote. -Adam
First off you are trying to send "C:\Sent\RobotSettings.txt", but you're telling the receiver that he is receiving "test.jpg", this will give you a strange result.
Furthermore you need to pass the port on which the receiver should connect to begin downloading the file. This port is returned from the transfer objects GetPortNumber property.
But still even after fixing these minor things; your send_to_robot doesn't take that many arguments, you need to create a new subroutine for this or extend send_to_robot.
VB.NET Code:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSendFile.Click
Dim transfer As New FileTransferSend("C:\Sent\RobotSettings.txt")
Almost there. I was able to fix the problems on the sending side. All im having trouble with now is getting the ip address out of the message I send and into the start file receive statement.
test Code:
Private Function Start_File_Transfer(ByVal message As String) As Integer
Dim IPAddress, PortNumber, FileName, FileSize As String
Dim transfer As New FileTransferReceive(IPAddress, PortNumber, FileName, FileSize)
' Add it to a collection of some sort, and add the eventhandlers for TransferFinished and TransferFailed.
End Function
The error Reads: Value of type 'String' cannot be converted to 'System.Net.IPAddress'. The ipaddress variable right after FileTransferRecieve( is what has the blue line under it.
You actually do not need to send the IP address to the receiver. If you have a socket for the connection to the sender (which you should), you can get its IP like this:
VB.NET Code:
Dim addr As System.Net.IPAddress = DirectCast(sock.RemoteEndPoint, System.Net.IPEndPoint).Address
Awsome, Thankyou soo much for the help. I got it to work. The last 1 last thing that I am curious about. How would I display the progress of the filetransfer in a progress bar? I tried adding the progressbar1.value = BytesRead code to the loop that sends the file, but it mess's up the transfer and only sends the first 8kb and stops, and also dosent increment the progress bar. I set the maximum value of the progress bar to the total amount of bytes of the file. Hope you can help me out with this . -Adam
Note that you the download occurs on a separate thread, and since we are raising this event from the same thread, you can not access your forms controls directly from the eventhandler.
By the way, are you adding the transfers to a collection after creating them?
I understand about the threading. I have a display delegate that I think will be able to handle changing the progress bar. I use it to add the data to list box from the sockets and serial port. As for the transfers to a collection, Im not sure what your talking about so im going to say no. lol. Also, I need to display the sent data on the sending side not the receiving side. One other thing, The raise events, how would you add code to them, so they execute it when that even happens? Like displaying a message when a transfer fails? I think thats it for now. Thank you for putting up with my ignorance. -Adam
I understand about the threading. I have a display delegate that I think will be able to handle changing the progress bar. I use it to add the data to list box from the sockets and serial port. As for the transfers to a collection, Im not sure what your talking about so im going to say no. lol.
Hmm well lets ignore this part for a bit then, lets see if it works without it.
Originally Posted by adamj12b
Also, I need to display the sent data on the sending side not the receiving side.
Then just do the modifications i showed you in the FileTransferReceive in the FileTransferSend class instead
Originally Posted by adamj12b
One other thing, The raise events, how would you add code to them, so they execute it when that even happens? Like displaying a message when a transfer fails?
To add a handler for an event you use the AddHandler statement right after creating your FileTransferReceive/FileTransferSend class instance,
Private Sub TransferFailedHandler(ByVal sender As FileTransferReceive, ByVal file As String)
'sender is a reference to the transfer that failed.
'file is the name of the file that didnt download properly.
End Sub
In this case, TransferFailedHandler will be called everytime a TransferFailed event is raised. Just do the same on the other events, the only thing to keep in mind is that the eventhandlers signature must be identical with the events signature. In this case the signature is: (ByVal sender As FileTransferReceive, ByVal file As String)
Originally Posted by adamj12b
I think thats it for now. Thank you for putting up with my ignorance. -Adam
I wasnt sure how to get the total size of the file into it, so I called the open dialog to get the file path and the get file size function. Is there something better I should use?
Also, This is the code that dose it all.
btnSendFile Code:
Private Sub btnSendFile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSendFile.Click
Dim strHostName, strIpAddress, strFilePath, strFileName As String '**********
OFD1.ShowDialog() '**********
strFilePath = OFD1.FileName '**********
strFileName = OFD1.SafeFileName '**********
Dim transfer As New FileTransferSend(strFilePath) '**********
underneath the "AddressOf TransferProgressChangedHandler" I get this error message:
Error 1 Method 'Private Sub TransferProgressChangedHandler(sender As FileTransfer.FileTransferSend, file As String)' does not have the same signature as delegate 'Delegate Sub TransferProgressChangedEventHandler(sender As FileTransferSend, current As Long, maximum As Long)'. F:\Visual Basic\FileTransferSend\FileTransferSend\frmMain.vb 215 64 FileTransferSend
Not too sure what that means. Hopefully you can let me kno if everything looks good also. Thanks. -Adam
P.S. How do you get your vb code come up all colored and nice looking?
That error is caused by the fact that the TransferProgressChanged event has this signature: (ByVal sender As FileTransferReceive, ByVal current As Long, ByVal maximum As Long)
And you're trying to add an eventhandler to it that looks like this:
VB.NET Code:
Private Sub TransferProgressChangedHandler(ByVal sender As FileTransferSend, ByVal file As String) '**********
DisplayMessage("PRG#" & "100")
'sender is a reference to the transfer that failed.'**********
'file is the name of the file that didnt download properly.'**********
End Sub '**********
It needs to look like this:
VB.NET Code:
Private Sub TransferProgressChangedHandler(ByVal sender As FileTransferReceive, ByVal current As Long, ByVal maximum As Long) '**********
DisplayMessage("PRG#" & "100")
'sender is a reference to the transfer that failed.'**********
'file is the name of the file that didnt download properly.'**********
End Sub '**********
About making the code colored, you have to specify that it is VB.NET code you're highlighting by wrapping it in:
Cool, That fixed all the errors, but it dosent work anymore either lol. For some reason whenever I send a file it only sends the first 8kb which would be 1 full buffer, then it calls the transfer failed handler,(which at least I know that that works) then it shows my message box that says that something is wrong. since there are no errors im not sure where to go. I tried to put a break point thinking the the raise even that changes the progress bar might be causing the loop that sends the data to only run once, but the progress bar never changes and TransferProgressChangedHandeler never even gets called. The break was never reached. Im attaching both projects in there newest forms. -Adam
I tried putting that in a few different places with no success. The same thing as before keeps happening. If I try to put that line in the form class it says m_file is not declared, and the only place that it dosent say that is inside the class file. It dosent make any since to me because the place that needs the file length info is inside the form class under that send file button. -Adam
Re: [RESOLVED] [2005] .NET Sockets File Transfer Help
Yep everything works great. The progress bar progresses as the file is transfered and I added code to the finished and failed handlers on the send side, because that is the only place that they are needed because the receive side dosent even have a monitor. The display delegate that I had worked fine for changing the value of the progress bar. The only thing that im not too sure of is what will happen if I try to add a message to the list box with the delegate while sending a file with the bar updating. maybe there is a better way to change the bar without using that delegate. Not the biggest deal though. Again thanks. -Adam
Re: [RESOLVED] [2005] .NET Sockets File Transfer Help
Ah yes this project, I'm considering submitting these classes to the codebank. If you come across anything that needs change or fixing, please do tell.
One thing it looks like I've failed to mention is just to be careful not handle the TransferProgressChanged event and do too much work in its eventhandler, as it'll be invoked on the same thread that transfers the file, it'll basically halt the transfer for as long as the eventhandler takes to execute.
If you need to perform alot of work in the eventhandler, a solution is to directly invoke a method on the UI thread (using Me.Invoke in the eventhandler), and perform the work there instead.
Re: [RESOLVED] [2005] .NET Sockets File Transfer Help
Hi Adam,
I'm working on similar project and your project is really really helpful, because i'm a starter and dnt know much about programming..is there any way i can modify the program to run both the server and client on single machine (one Computer)? like using localhost (127.0.0.1)..please i need your help asap..i have tried running both server and client on my computer but it does not establish connection between the server and the client..cheers man, thnx for helping.