Galahad 0 Report post Posted March 7, 2008 Recently, I had a need to make a FTP client, since our webhosting FTP server was kind of exotic, and very restrictive, and most of uploads, even though they reach 100% would crash... File would be uploaded to a server, but FTP clients just froze upon completion, waiting for the 226 (OK) from FTP server... So, I had to make my own, one who would not wait for 226, but instead, watch the file pload progress... This tutorial is not fuly complete, in the sense that it does not offer COMPLETE FTP client functionality (for example, I ddn't write the code for FTP download, though it is fairly easy to add it, since all the necessary functions are already written)... I was ofcourse guided by the thought that tutorials sould encourage someone to do some further reading and exploration of their own, not just copy/paste... First, let's start off with how FTP works... FTP uses 2 ports to communicate: port 21 for command communication, and some other port for data transmission... So, knowing this, let's begin: First off, we need to declare some variables we'll use in our code: Option ExplicitDim CData As String ' We'll use this to store incoming FTP dataDim CResp As String ' We'll use this to store response from FTP serverDim DataOK As Boolean ' Is the data sent?Dim CmdOK As Boolean ' Is the command sent?Dim ATS As Single ' Approximate transfer speedDim ATT As Single ' Approximate transfer timeDim Data As String ' We take chunks of data we receive from the server, and merge them in this variableDim p_Log As Boolean ' Should we log FTP activity?Private Const C_TIMEOUT As Single = 1 ' Default timeout value of 1 secondDim ConnLog As New Collection OK, next, we'll need several of the controls on the Form:2x Winsock controls: wskFTPC and wskFTPD 1x Command button: Command1 1x Text box: Text1 1x Timer: Timer1; resolution 100ms OK, that set, let's add some actual FTP code.. Since many of FTP commands will often be called, so to avoid repetition, we'll write several of the functions and subs: Private Function CSend(ByVal Command As String) As BooleanIf CmdOK Then CmdOK = False CSend = False wskFTPC.SendData Command & vbCrLf ConnLog.Add "-> " & Command If p_Log Then Text1.Text = Text1.Text & ("-> " & Command & vbCrLf) End If CSend = WaitCOKEnd IfEnd FunctionPrivate Function DSend(ByVal Data As String) As BooleanIf DataOK Then DataOK = False wskFTPD.SendData Data DSend = WaitOKEnd IfEnd Function We will call CSend() every time we want to send a command, and DSend() every time we send data chunk to a server. Let's move on... You must have noticed some more of the functions here, so let's write them (and others) too: Public Sub Wait(ByVal ms As Single)Dim t1 As Single, t2 As Singlet1 = TimerWhile t2 < t1 + ms DoEvents t2 = TimerWendEnd SubPublic Function GetCode(Optional ByVal Timeout As Single = C_TIMEOUT) As StringDim t1 As Single, t2 As SingleCResp = ""GetCode = ""t1 = TimerWhile CResp = "" t2 = Timer If t2 > t1 + Timeout Then Exit Function DoEventsWendGetCode = CRespEnd FunctionPublic Function WaitCode(ByVal Code As String, Optional ByVal Timeout As Single = C_TIMEOUT) As BooleanDim t1 As Single, t2 As Singlet1 = TimerWaitCode = FalseWhile CResp <> Code t2 = Timer If t2 > t1 + Timeout Then Exit Function DoEventsWendWaitCode = TrueEnd FunctionPublic Function WaitOK(Optional ByVal Timeout As Single = C_TIMEOUT) As BooleanDim t1 As Single, t2 As Singlet1 = TimerWaitOK = FalseWhile DataOK = False t2 = Timer If t2 > t1 + Timeout Then Exit Function DoEventsWendWaitOK = TrueEnd FunctionPublic Function WaitCOK(Optional ByVal Timeout As Single = C_TIMEOUT) As BooleanDim t1 As Single, t2 As Singlet1 = TimerWaitCOK = FalseWhile CmdOK = False t2 = Timer If t2 > t1 + Timeout Then Exit Function DoEventsWendWaitCOK = TrueEnd FunctionPublic Function WaitConn(Optional ByVal Timeout As Single = C_TIMEOUT) As BooleanDim t1 As Single, t2 As Singlet1 = TimerWaitConn = FalseWhile wskFTPD.State <> sckConnected t2 = Timer If t2 > t1 + Timeout Then Exit Function If wskFTPD.State = sckConnecting Then t1 = Timer DoEventsWendWaitConn = TrueEnd FunctionPrivate Function SendPORT() As BooleanDim pIP As StringDim pPort As StringDim pH As LongDim pL As LongDim lPort As LongRandomize TimerlPort = Int(12000 * Rnd + 6000)SendPORT = FalsepH = lPort \ 256pL = lPort - (pH * 256)pPort = Trim(CStr(pH)) & "," & Trim(CStr(pL))With wskFTPD .LocalPort = pH * 256 + pL pIP = .LocalIP .ListenEnd WithpIP = Replace(pIP, ".", ",")CSend ("PORT " & pIP & "," & pPort)If Not WaitCode("200") Then Exit FunctionSendPORT = TrueEnd FunctionPrivate Function SendLIST(Optional ByVal FilePath As String = "") As BooleanData = ""CSend ("LIST" & IIf((FilePath = ""), "", " " & FilePath))If Not WaitCode("150") Then Exit FunctionWhile wskFTPD.State = sckConnected DoEvents Label3.Caption = CRespWendOpen "c:\incoming" For Binary As #120Put #120, 1, DataClose #120Data = ""SendLIST = TrueEnd FunctionPrivate Function SendFile(ByVal FileName As String, Optional ByVal BuffSize As Long = 2048) As BooleanDim hFile As IntegerDim fBuff As StringDim lBuff As LongDim t1 As SingleDim t2 As SingleDim s As Long, i As Long, r As LonghFile = FreeFilelBuff = BuffSizet1 = TimerOpen FileName For Binary As #hFile If LOF(hFile) >= lBuff Then s = LOF(hFile) \ lBuff Picture1.ScaleWidth = s Label1.Width = 0 fBuff = Space(lBuff) For i = 1 To s Get #hFile, , fBuff DSend fBuff Label1.Width = i DoEvents Next i r = LOF(hFile) r = r - (lBuff * s) If r > 0 Then fBuff = Space(r) Get #hFile, , fBuff DSend fBuff End If Label1.Width = LOF(hFile) Else Picture1.ScaleWidth = LOF(hFile) fBuff = Space(LOF(hFile)) Get #hFile, , fBuff DSend fBuff Label1.Width = LOF(hFile) End If DoEvents t2 = Timer ATS = LOF(hFile) / ((t2 - t1) + 1) ATT = t2 - t1Close #hFilewskFTPD.CloseSendFile = TrueEnd Function Okie, now we've written all of the functions we'll need... Next on, we need to add some event handlers: Private Sub Timer1_Timer()Label2.Caption = wskFTPD.StateIf wskFTPD.State = sckClosing Then wskFTPD.CloseEnd SubPrivate Sub wskFTPC_SendComplete()CmdOK = TrueDoEventsEnd SubPrivate Sub Form_Unload(Cancel As Integer)If wskFTPC.State = 7 Then Text1.Text = Text1.Text & CSend("QUIT") wskFTPC.CloseElse wskFTPC.CloseEnd IfEnd SubPrivate Sub wskFTPD_ConnectionRequest(ByVal requestID As Long)wskFTPD.ClosewskFTPD.Accept requestIDText1.Text = Text1.Text & "*** Data connection established" & vbCrLfEnd SubPrivate Sub wskFTPD_DataArrival(ByVal bytesTotal As Long)Dim s As StringwskFTPD.GetData sData = Data & sEnd SubPrivate Sub wskFTPD_SendComplete()DataOK = TrueDoEventsEnd Sub OK, that's settled too... We've written basic FTP handling, upload will work, download too, but you'll have to come up with your own download function, that wraps around existing functions Now that we've got all the ingredients, let's make a juicy FTP soup: Private Sub Command1_Click()CmdOK = TrueDataOK = Truep_Log = TruewskFTPC.RemoteHost = "ftphost.com"wskFTPC.RemotePort = 21wskFTPC.ConnectIf Not WaitCode("220") Then Exit SubCSend ("USER username")If Not WaitCode("331") Then Exit SubCSend ("PASS password")If Not WaitCode("230") Then Exit SubCSend ("TYPE I")If Not WaitCode("200") Then Exit SubCSend ("CWD sautpro.com/proba")If Not WaitCode("250") Then Exit SubIf Not SendPORT Then Exit SubCSend ("STOR somefile")If Not WaitCode("200") Then Exit SubIf Not WaitConn Then Exit SubIf Not SendFile("c:\.somefile") Then Exit SubIf Not WaitCode("226", 10) Then CSend "NOOP" If Not WaitCode("226", 20) Then Exit SubEnd IfText1.Text = Text1.Text & "*** File transfer complete. (Approx. upload speed " & Format(ATS / 1024, "###,##0.00") & "kb/s, Approx. upload time " & Format(ATT, "#,##0.00") & " seconds)" & vbCrLfText1.Text = Text1.Text & "*** Closing data connection." & vbCrLfCSend ("TYPE A")If Not WaitCode("200") Then Exit SubIf Not SendPORT Then Exit SubSendLISTIf Not WaitCode("226", 5) Then CSend "NOOP" If Not WaitCode("226", 10) Then Exit SubEnd IfText1.Text = Text1.Text & "*** Directory LISTing received." & vbCrLfEnd Sub Now, remember to replace ftphost.com, yourfile, username and password with actual values, or this won't work... So, what are we doing? First, we're initializing variables, set wskFTPC to connect to ftphost.com on port 21 (FTP command port)... Then, we send our login info, and inbetween we wait for appropriate responses... Since I made this for specific purpose, error handling is virtualy non-existent, but it's easy to add to this code. You can find a list of FTP responses on the net... I believe code is rather self-explanatory, but if you have any questions regarding this, I'm at your service, just post here, or drop me a PM... You can play around with the code, optimise buffer size for upload, for download, since I used a value that suited best to my internet connection and FTP server type... This ofcourse is not a complete FTP client, it's only a core functionality of FTP... If you wish to build some sort of full blown FTP client, you'll have to work some more on this code... Oh, and if you do make that FTP client based on this code, I'd like it if you put my name somewhere in the credits Cheers, and I hope you will find this usefull in some way... Share this post Link to post Share on other sites
iGuest 3 Report post Posted July 18, 2008 upload text file Ftp In Visual Basic 6.0 I am currently working on some software and I need this program to upload a small text file to an ftp server. After reading this tutorial, it seems like this would be pretty simple for you to do. I've been looking all over the internet to find help with this, and every time I think I find something, it doesn't work, and the author is no help. Please help! many many many many thanks!! Ethan -question by Ethan Share this post Link to post Share on other sites
iGuest 3 Report post Posted October 14, 2008 Cant get thething to work (does not wait for anything) Ftp In Visual Basic 6.0 Replying to iGuest Al it does is exit sub and sit with state at 0, never changing. I tracew it through and canno see how it can work. The logic I see is send command and weait for response, however to exit sub you can never go back!. No lops till timeout or anything I would expect. Explain please? -reply by Martin Share this post Link to post Share on other sites
iGuest 3 Report post Posted November 10, 2008 Webbrowser control vb to connect to ftp.Ftp In Visual Basic 6.0I want the webbrowser control to open ftp.I can connct the ftp using MYUSER:MYPASS@myhost, but that makes the user and pass visible when browsing the histroy of the browser.How can I make the control to fill in the password and user automatically without being visible in the url?Thanks in advance,Roei.-reply by roei Share this post Link to post Share on other sites