Click here to Skip to main content
15,881,172 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have a program that automatically download a file from FTP Server

I have a code that runs thru BackgroundWorker that download a file and it works fine.

The problem is when I try using three BackgroundWorkers that downloads a different files at the same time, there's one file that I can't download (Operation has Time Out) neither the three BackgroundWorkers.

I can download the Error File(the file that I can't download) when one of the other BackgroundWorkers finish downloading the file.(I can do this because I have a loop that when the BackgroundWorker can't download the file it will try to download again)

Same error will happen to the BackgroundWorker when theres a two BackgroundWorker that starts its download.

What causes this error to occur? Is it in the FTP Server or my codes?
Actually I doubt that the FTP Server will cause that error because I saw an application that downloads a file from FTP Server(same FTP Server) and it can download ten files at the same time but its not Auto Download. But I don't know if that's right.

Any suggestions appreciated.

Thanks. . .

Revision:

'THIS IS THE BACKGROUND WORKER THAT DOWNLOADS THE UPLOAD REPORTS
'I use the OLEDB to get data from an excel file cause I want the program to run even if the computer don't have an Excel 'Application installed
'I'm putting the data to a Master List then if the Master List has a value a Timer will start the download process
VB
Private Sub bckReport_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bckReport.DoWork
    Dim MyConnection As OleDbConnection
    Dim DtSet As DataSet
    Dim MyCommand As OleDbDataAdapter

    Me.Invoke(safeLogs, "Connecting to FTP Server...", "", ftpSite, saveTo)

    Dim request As FtpWebRequest = Nothing
    Dim response As FtpWebResponse = Nothing
    request = DirectCast(WebRequest.Create(ftpSite + Format(Now, "ddMMyyyy")), FtpWebRequest)
    request.Method = WebRequestMethods.Ftp.ListDirectory
    request.Credentials = New NetworkCredential(username, password)
    response = DirectCast(request.GetResponse(), FtpWebResponse)
    Dim responseStream As Stream = response.GetResponseStream()
    Dim reader As New StreamReader(responseStream)
    Dim CrLf As Char() = {vbCr, vbLf}
    Dim lines() As String = reader.ReadToEnd().Split(CrLf, StringSplitOptions.RemoveEmptyEntries)

    Dim ctr As Integer = 0
    For i As Integer = 0 To UBound(lines)
        If lines(i).EndsWith(".xls") Then ctr = ctr + 1
    Next i

    Me.Invoke(safeLogs, "Downloading " & ctr & " Upload Report(s)...", "", ftpSite + Format(Now, "ddMMyyyy") + "/", saveTo)

    For i As Integer = 0 To UBound(lines)

        TimerReport.Enabled = False

        If Not Directory.Exists(saveTo + "tmp\") Then
            Directory.CreateDirectory(saveTo + "tmp\")
        End If

        If Not File.Exists(saveTo + "tmp\" + lines(i)) And lines(i).EndsWith(".xls") Then

            Dim outputStream As New FileStream(saveTo + "tmp\" + lines(i), FileMode.Create)
            Dim ftpStream As Stream

            Try
                request = DirectCast(FtpWebRequest.Create(New Uri(ftpSite + Format(Now, "ddMMyyyy") + "/" + lines(i))), FtpWebRequest)
                request.Method = WebRequestMethods.Ftp.DownloadFile
                request.UseBinary = True
                request.Credentials = New NetworkCredential(username, password)
                response = DirectCast(request.GetResponse(), FtpWebResponse)
                ftpStream = response.GetResponseStream()

                Dim bufferSize As Integer = 10000 'size of maximum download
                Dim readCount As Integer
                Dim buffer As Byte() = New Byte(bufferSize - 1) {}

                readCount = ftpStream.Read(buffer, 0, bufferSize)

                While readCount > 0
                    outputStream.Write(buffer, 0, readCount)
                    readCount = ftpStream.Read(buffer, 0, bufferSize)
                End While

                outputStream.Close()


                MyConnection = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; " & _
                            "Data Source='" & saveTo + "tmp\" + lines(i) & " '; " & "Extended Properties=""Excel 8.0;HDR=NO;IMEX=1"";")

                MyCommand = New OleDbDataAdapter("SELECT * FROM [" + Mid(lines(i), 1, Len(lines(i)) - 4) + "$];", MyConnection)
                MyCommand.TableMappings.Add("Table", "Attendence")

                DtSet = New DataSet

                MyCommand.Fill(DtSet)

                Dim safePopulateDatGridView As New PopulateDatGridViewSafe(AddressOf PopulateDatGridView)
                Me.Invoke(safePopulateDatGridView, DtSet)

                MyConnection.Close()

                For j As Integer = 1 To dtgView.RowCount - 1
                    If dtgView.Item(1, j).Value = "" And dtgView.Item(3, j).Value = "" Then
                        Exit For
                    End If
                    'Job Information | FTP Site | Excel File Location | Image Count
                    downloadList.Add(dtgView.Item(1, j).Value + "|" + ftpSite + Format(Now, "ddMMyyyy") + "/" + dtgView.Item(3, j).Value + "|" + saveTo + "tmp\" + lines(i) + "|" + dtgView.Item(5, j).Value)
                Next j

            Catch ex As Exception
                Me.Invoke(safeLogs, ex.Message.ToString + " Downloading again...", "Error in Upload Report.", ftpSite + Format(Now, "ddMMyyyy") + "\" + lines(i), saveTo + lines(i))
                outputStream.Close()
                File.Delete(saveTo + "tmp\" + lines(i))
                i = i - 1
            End Try
        End If

    Next i

End Sub



'This is the Timer that starts the download process
'I separate the data from a Master List putting it to 3 List each one for each BackgrounWorker to process
VB
Private Sub TimerStart_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TimerStart.Tick

    If downloadList.Count > 0 Then
        Dim readyList As ArrayList = New ArrayList
        For i As Integer = 0 To downloadList.Count - 1
            readyList.Add(downloadList.Item(i))
        Next i

        For i As Integer = 0 To downloadList.Count - 1
            downloadList.Remove(readyList.Item(i))
        Next i

        For i As Integer = 0 To readyList.Count - 1
            If list2.Count < list1.Count And list2.Count < list3.Count Then
                list2.Add(readyList.Item(i))
            ElseIf list1.Count = list2.Count Then
                list1.Add(readyList.Item(i))
            Else
                list3.Add(readyList.Item(i))
            End If
        Next i

        If Not bckDownloader1.IsBusy Then bckDownloader1.RunWorkerAsync()
        If Not bckDownloader2.IsBusy Then bckDownloader2.RunWorkerAsync()
        If Not bckDownloader3.IsBusy Then bckDownloader3.RunWorkerAsync()
    End If
End Sub


'BACKGROUNDWORKERS
'I have same process the difference is the variable and function I access
'ftp1 = the FTP file site
'list1 = list of downloads
'fileName1 = filename
'request1 = FtpWebRequest
'response1 = FtpWebResponse

'When this BackgorundWorker starts it will not stop getting in from list (Do While list1.Count > 0)
VB
Private Sub bckDownloader1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bckDownloader1.DoWork

    Me.Invoke(safeButtonEnable, 2)

    Dim downloaded As Long
    Dim elapseTime As New Stopwatch

    Dim safeDownloadStatus As New DownloadStatusSafe1(AddressOf DownloadStatus1)

    Do While list1.Count > 0

        Dim lstArr As Object = Split(list1.Item(0), "|")

        Dim saveLocation As String = saveTo + Format(Now, "ddMMyyyy") + "\" + lstArr(0) + "\"

        If Not Directory.Exists(saveTo + Format(Now, "ddMMyyyy") + "\") Then
            Directory.CreateDirectory(saveTo + Format(Now, "ddMMyyyy") + "\")
        End If

        If Not Directory.Exists(saveTo + Format(Now, "ddMMyyyy") + "\" + lstArr(0)) Then
            Directory.CreateDirectory(saveTo + Format(Now, "ddMMyyyy") + "\" + lstArr(0))
        End If

        Dim logStr As String
        Dim del As String = list1.Item(0)

        ftp1 = lstArr(1)
        fileName1 = Split(ftp1, "/")(UBound(Split(ftp1, "/")))

        If Not (File.Exists(saveLocation + Split(lstArr(2), "\")(UBound(Split(lstArr(2), "\"))))) Then
            File.Copy(lstArr(2), saveLocation + Split(lstArr(2), "\")(UBound(Split(lstArr(2), "\"))))
        End If

        File.Delete(lstArr(2))

        If Not (File.Exists(saveLocation + fileName1)) Then

            Dim outputStream As New FileStream(saveLocation + fileName1, FileMode.Create)
            Dim ftpStream As Stream

            Try
                downloaded = 0
                elapseTime.Reset()

                elapseTime.Start()

                Me.Invoke(safeLogs, "Downloading " & fileName1, "", ftp1, saveLocation)
                Me.Invoke(safeDownloadStatus, fileName1, 0, 0, 0, 2)

                Dim FTPfileSize As Long = GetFTPFileSize1(saveLocation)

                If FTPfileSize > 0 Then

                    logStr = lstArr(0) + "," + Format(Now, "ddMMyyyy") + "," + fileName1 + "," + Format(Now, "hh:mm:ss tt").ToString + "," + lstArr(3)

                    request1 = DirectCast(FtpWebRequest.Create(New Uri(ftp1)), FtpWebRequest)
                    request1.Method = WebRequestMethods.Ftp.DownloadFile
                    request1.UseBinary = True
                    request1.Credentials = New NetworkCredential(username, password)
                    response1 = DirectCast(request1.GetResponse(), FtpWebResponse)
                    ftpStream = response1.GetResponseStream()

                    Dim bufferSize As Integer = 10000 'size of maximum download
                    Dim readCount As Integer
                    Dim buffer As Byte() = New Byte(bufferSize - 1) {}

                    readCount = ftpStream.Read(buffer, 0, bufferSize)

                    While readCount > 0
                        If bckDownloader1.CancellationPending Then 'If user abort download
                            Me.Invoke(safeButtonEnable, 1)
                            outputStream.Close()
                            File.Delete(saveLocation + fileName1)
                            Exit Do
                        End If

                        downloaded = downloaded + readCount

                        outputStream.Write(buffer, 0, readCount)
                        readCount = ftpStream.Read(buffer, 0, bufferSize)

                        Me.Invoke(safeDownloadStatus, fileName1, elapseTime.ElapsedMilliseconds, downloaded, FTPfileSize, 1)
                    End While

                    Me.Invoke(safeLogs, fileName1 + " has been downloaded...", "Panel(1) Downloading File.", ftp1, saveLocation + fileName1)

                    logStr = logStr + "," + Format(Now, "hh:mm:ss tt").ToString

                    elapseTime.Stop()

                    list1.Remove(del)
                Else
                    outputStream.Close()
                    File.Delete(saveLocation + fileName1)
                End If
            Catch ex As Exception
                Try
                    Me.Invoke(safeLogs, ex.Message.ToString + " Downloading again...", "Panel(1) Downloading File.", ftp1, saveLocation + fileName1)
                    outputStream.Close()
                    File.Delete(saveLocation + fileName1)
                Catch ex1 As Exception
                End Try
            End Try
        Else
            Me.Invoke(safeLogs, fileName1 + " has been downloaded...", "Panel(1) Downloading File.", ftp1, saveLocation + fileName1)

            logStr = fileName1 + "already exist in folder directory " + saveLocation

            elapseTime.Stop()

            list1.Remove(del)
        End If
    Loop

    Me.Invoke(safeDownloadStatus, "", 0, 0, 0, 3)
End Sub
Posted
Updated 6-Dec-11 23:36pm
v6
Comments
Sergey Alexandrovich Kryukov 7-Oct-11 15:45pm    
Hard to say anything without looking at the code...
--SA

1 solution

BackgroundWorker runs on separate thread.
If one affects the others, my best guess is that your code isn't threadsafe.

My suggestion:
1. Make all global variables and objects local to your code.
2. Synchronize access to vars and objects that cannot be localized.

The idea is to make your code independent and isolated from external changes.

Good luck.

Post your code if you want better help.
 
Share this answer
 
Comments
hansoctantan 8-Oct-11 10:49am    
I have a global variable declare, 3 FtpWebRequest, 3 FtpWebResponse each one for each BackgroundWorker. Also I use different functions for each BackgroundWorker too so I can't change anything to the other BackgroundWorker.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900