Tom Beck
asked on
VB.Net FTP login Class almost works, need help
I found this sample class file code online and it almost works. That is, it works when I step through the code in debug mode on my VS 2005. The output I get in debug mode looks like this:
USER ftpUser
220 Microsoft FTP Service
331 Password required for ftpUser.
PASS ftpPassword
230 User ftpUser logged in.
However, when I run it without debugging it fails and I get this:
USER ftpUser
220 Microsoft FTP Service
PASS ftpPassword
331 Password required for ftpUser.
It looks like the password is being sent before the 331 response.
Should I add code to check for the 331 response before sending the password or am I mistaken about the problem? How do I check for the 331?
USER ftpUser
220 Microsoft FTP Service
331 Password required for ftpUser.
PASS ftpPassword
230 User ftpUser logged in.
However, when I run it without debugging it fails and I get this:
USER ftpUser
220 Microsoft FTP Service
PASS ftpPassword
331 Password required for ftpUser.
It looks like the password is being sent before the 331 response.
Should I add code to check for the 331 response before sending the password or am I mistaken about the problem? How do I check for the 331?
Public Class ftpCreate
Private ftpTcpClient As TcpClient
Public ResponseStream As NetworkStream
Public ReturnNameMessage As String
Public ReturnPwdMessage As String
Public Sub ftpLogin(ByVal strName As String, ByVal strPWD As String, ByVal strftpLogin As String)
Try
Dim strCommand As String
Dim strReturnMessage As String
Dim bteSendBytes() As Byte
Dim bteReturnBytes() As Byte
Dim intReturnByteLength As Integer
Dim ftpTcpClient As TcpClient = New TcpClient(strftpLogin, 21)
ResponseStream = ftpTcpClient.GetStream
strCommand = "USER " + strName + vbCrLf
bteSendBytes = Encoding.ASCII.GetBytes(strCommand)
ResponseStream.Write(bteSendBytes, 0, bteSendBytes.Length)
intReturnByteLength = ftpTcpClient.ReceiveBufferSize
ReDim bteReturnBytes(intReturnByteLength)
ResponseStream.Read(bteReturnBytes, 0, intReturnByteLength)
strReturnMessage = Encoding.ASCII.GetString(bteReturnBytes) + "/ "
ReturnNameMessage = strCommand + strReturnMessage
strCommand = "PASS " + strPWD + vbCrLf
Array.Clear(bteSendBytes, 0, bteSendBytes.Length)
bteSendBytes = Encoding.ASCII.GetBytes(strCommand)
ResponseStream.Write(bteSendBytes, 0, bteSendBytes.Length)
intReturnByteLength = ftpTcpClient.ReceiveBufferSize
ReDim bteReturnBytes(intReturnByteLength)
ResponseStream.Read(bteReturnBytes, 0, intReturnByteLength)
strReturnMessage = Encoding.ASCII.GetString(bteReturnBytes) + "/ "
ReturnPwdMessage = strCommand + strReturnMessage + vbCrLf
Catch ex As SocketException
ReturnPwdMessage = ex.Message
End Try
End Sub
End Class
Try adding a Thread.Sleep(500) call to add some delay before sending the password.
ASKER
CodeCruiser,
That works when the delay is added immediately after the USER is sent but before the response is read (didn't work further down than that in the process). My concern is this. I am writing a utility that will be offered to others. What if someone has a really slow connection. How much delay would be required to cover all possibilities? Instead, is there a way to check that the response on the USER request is complete with the 331 before sending the password?
That works when the delay is added immediately after the USER is sent but before the response is read (didn't work further down than that in the process). My concern is this. I am writing a utility that will be offered to others. What if someone has a really slow connection. How much delay would be required to cover all possibilities? Instead, is there a way to check that the response on the USER request is complete with the 331 before sending the password?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
CodeCruiser,
The code below is my attempt to combine both of your suggestions. It adds a half second delay if the strReturnMessage does not contain 331 but limits the total delay to 10 seconds so it's not waiting forever. On my connection, it's adding one half second delay before sending the password. It works.
I am a novice programmer, so tell me if I don't have all bases covered.
Thanks for the help.
The code below is my attempt to combine both of your suggestions. It adds a half second delay if the strReturnMessage does not contain 331 but limits the total delay to 10 seconds so it's not waiting forever. On my connection, it's adding one half second delay before sending the password. It works.
I am a novice programmer, so tell me if I don't have all bases covered.
Thanks for the help.
Public Class ftpCreate
Private ftpTcpClient As TcpClient
Public ResponseStream As NetworkStream
Public ReturnNameMessage As String
Public ReturnPwdMessage As String
Public Sub ftpLogin(ByVal strName As String, ByVal strPWD As String, ByVal strftpLogin As String)
Try
Dim strCommand As String
Dim strReturnMessage As String = ""
Dim bteSendBytes() As Byte
Dim bteReturnBytes() As Byte
Dim intReturnByteLength As Integer
Dim timeCheck As Integer = 0
Dim ftpTcpClient As TcpClient = New TcpClient(strftpLogin, 21)
ResponseStream = ftpTcpClient.GetStream
strCommand = "USER " + strName + vbCrLf
bteSendBytes = Encoding.ASCII.GetBytes(strCommand)
ResponseStream.Write(bteSendBytes, 0, bteSendBytes.Length)
intReturnByteLength = ftpTcpClient.ReceiveBufferSize
ReDim bteReturnBytes(intReturnByteLength)
Do Until strReturnMessage.Contains("331")
ResponseStream.Read(bteReturnBytes, 0, intReturnByteLength)
strReturnMessage = Encoding.ASCII.GetString(bteReturnBytes) + "/ "
System.Threading.Thread.Sleep(500)
timeCheck = timeCheck + 500
If timeCheck > 10000 Then
ReturnNameMessage = "User " & strName & " not accepted, timed out."
Exit Try
Else
ReturnNameMessage = strCommand + strReturnMessage
End If
Loop
timeCheck = 0
strCommand = "PASS " + strPWD + vbCrLf
Array.Clear(bteSendBytes, 0, bteSendBytes.Length)
bteSendBytes = Encoding.ASCII.GetBytes(strCommand)
ResponseStream.Write(bteSendBytes, 0, bteSendBytes.Length)
intReturnByteLength = ftpTcpClient.ReceiveBufferSize
ReDim bteReturnBytes(intReturnByteLength)
ResponseStream.Read(bteReturnBytes, 0, intReturnByteLength)
strReturnMessage = Encoding.ASCII.GetString(bteReturnBytes) + "/ "
ReturnPwdMessage = strCommand + strReturnMessage + vbCrLf
Catch ex As SocketException
ReturnPwdMessage = ex.Message
End Try
End Sub
End Class
ASKER
Actually, this Do loop works better because it only adds the delay when necessary.
...
Do Until strReturnMessage.Contains("331")
If timeCheck > 10000 Then
ReturnNameMessage = "User " & strName & " not accepted, timed out."
Exit Try
Else
ResponseStream.Read(bteReturnBytes, 0, intReturnByteLength)
strReturnMessage = Encoding.ASCII.GetString(bteReturnBytes) + "/ "
If Not strReturnMessage.Contains("331") Then
System.Threading.Thread.Sleep(500)
timeCheck = timeCheck + 500
End If
ReturnNameMessage = strCommand + strReturnMessage
End If
Loop
...
The approach looks good to me. You may be novice but the good thing is that you just needed a hint to write your own code. You may want to implement this logic for all of the commands that you send so that you wait for response before sending the next command.