2010-03-11 63 views
2

我一直試圖在過去的兩天內解決這個問題的底部,而且我確實被卡住了。希望有些聰明的人可以幫助我。Delphi 2010中HTTPSend的突觸和字符串問題

問題是我有一個函數,我在一個線程中調用了一個從傳遞給它的網站下載文件(使用Synapse庫)的文件。但是,我發現每隔一段時間就會有一些網站不會下拉文件,但wget或Firefox/IE會毫無問題地下載它。

挖掘它,我發現了一些好奇的事情。下面是相關代碼:

uses 
//[..] 
    HTTPSend, 
    blcksock; 

//[..] 

type 
    TMyThread = class(TThread) 
    protected 
    procedure Execute; override; 
    private 
    { Private declarations } 
    fTheUrl: string; 
    procedure GetFile(const TheUrl: string); 
    public 
    property thrd_TheUrl: string read fTheUrl write fTheUrl; 
    end; 

implementation 

[..] 

procedure TMyThread.GetFile(const TheUrl: string); 
var 
    HTTP: THTTPSend; 
    success: boolean; 
    sLocalUrl: string; 
    IsSame : boolean; 
begin 

    HTTP := THTTPSend.Create; 
    try 
    HTTP.UserAgent := 
     'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727)'; 
    HTTP.ProxyHost := 'MYPROXY.COM'; 
    HTTP.ProxyPort := '80'; 

    sLocalUrl := 
     'http://web.archive.org/web/20071212205017/energizer.com/usbcharger/download/UsbCharger_setup_V1_1_1.exe'; 


    IsSame := SameText(sLocalUrl, sTheUrl); //this equals True when I debug 

    /// 
    /// 
    /// THIS IS WHERE THE ISSUE BEGINS 
    /// I will comment out 1 of the following when debugging 
    /// 
    HTTP.HTTPMethod('GET', sLocalUrl); // ----this works and WILL download the file 
    HTTP.HTTPMethod('GET', sTheUrl); // --- this always fails, and HTTP.ResultString contains "Not Found" 

    success := SysUtils.UpperCase(HTTP.ResultString) = 'OK'; 


    if HTTP.ResultCode > 0 then 
     success := True; //this is here just to keep the value around while debugging 
    finally 
    HTTP.Free; 
    end; 
end; 

procedure TMyThread.Execute 
begin 
    //fTheURL contains this value: http://web.archive.org/web/20071212205017/energizer.com/usbcharger/download/UsbCharger_setup_V1_1_1.exe 

    GetFile(fTheUrl); 
end; 

的問題是,當我分配一個局部變量的函數,並直接給它的URL,一切正常。但是,當將該變量傳遞給函數時,它失敗。有人有主意嗎?

HTTP.HTTPMethod('GET', sLocalUrl); // ----this works and WILL download the file 
    HTTP.HTTPMethod('GET', sTheUrl); // --- this always fails, and HTTP.ResultString contains "Not Found" 

我使用(從2天前的版本)的最新版本Synapse from their SVN repository

注意:我正在嘗試下載的文件是known to have a virus,我正在編寫的程序旨在下載惡意文件進行分析。所以,一旦你下載它,不要執行該文件。

但是,我使用這個URL b/c這是我可以重現問題。

+0

如果你從定義中刪除了「常量」發生什麼呢? – frogb 2010-03-11 22:33:48

+0

什麼也沒有改變。 – Mick 2010-03-11 23:57:05

+0

fTheUrl實際分配在哪裏?由於兩個字符串「邏輯上」具有相同的值,但其中一個有效,另一個沒有,那麼這讓我懷疑用於fTheUrl變量的內存。 – 2010-03-12 01:34:33

回答

0

嗯,我幾乎不好意思報告它,但我欠那些花時間回覆的人。

這個問題有什麼也沒有與突觸或TThread,但與網址區分大小寫事實有關!

在我的完整應用程序中,我有一個幫助URL函數(出於某種原因)的小函數。我刪除了,一切又開始工作......

4

您的代碼缺少您使用TMyThread類的關鍵細節。然而,你寫了

每隔一段時間有一些網站,它不會拉下文件,但wget或Firefox/IE將下載它沒有問題。

這聽起來像是一個時間問題。

每次都使用局部變量。使用函數參數僅適用於部分時間。這可能是由於功能參數不包含正確的URL 的一些時間

您需要注意的是,創建非掛起的線程可能會導致它在開始執行構建調用後的下一行之前立即開始執行(甚至可能完成)。因此,在線程創建後設置線程對象的任何屬性可能無效,因爲線程執行可能超過了讀取屬性的點。線程對象的fTheUrl字段最初將是一個空字符串,因此線程是否下載文件將取決於它之前的設置。

您的fTheUrl字段甚至沒有被同步原語保護。線程proc和主線程中的代碼都可以同時訪問它。以這種方式在線程之間共享數據是一件不安全的事情,可能會導致任何事情從錯誤的行爲到實際的崩潰。

如果您的線程真的用於下載單個文件,您應該刪除對該屬性的寫入訪問權限,並使用URL的參數編寫自定義構造函數。這將在線程啓動之前正確地初始化字段。

如果您要在程序中下載多個文件,您應該不會爲每個文件創建一個線程。使用一組線程(可能只有一個)將被分配文件下載。爲此,一個線程屬性是正確的解決方案,但是這需要通過同步來實現,並且當沒有文件被下載時該線程應該被阻塞,並且在該屬性被設置時解除阻塞。下載線程(或多個線程)將是生產者 - 消費者實現中的消費者。 Stack Overflow在Delphi標籤中有關於此的問題和解答,特別是在討論Suspend()Resume()的替代方案的問題中。

最後一件事:不要讓未處理的異常轉義Execute()方法。我不確定Delphi 2010是否處理VCL中的這些異常,但是線程中的未處理異常可能會導致應用程序崩潰或凍結等問題。

+0

創建一個未掛起的線程不會在構造器完成之前開始運行。這是圍繞德爾福5固定的。「delphi-2010」標籤暗示米克使用的是德爾福2010年。 – 2010-03-12 08:30:57

+0

@Rob:我沒有寫「當構造函數完成」時,我寫道「構造函數調用已經返回控制調用代碼「,這意味着'AfterConstruction()'等已經執行。我可能應該寫下「在執行主線程中的下一行之前」。 – mghie 2010-03-12 09:26:58

+0

感謝您的回覆,我發現在構建我的線程並將數據傳遞到此線程時會出現問題。如果我明確地傳遞了URL的文本,它會起作用,如果我傳遞了變量......失敗。我會繼續挖掘,我希望今天發佈解決方案。再次感謝你! – Mick 2010-03-12 13:40:46

0

請更新最後的Synapse修訂127