2013-01-18 66 views
2

我在爲每個IdTCPServer連接聲明一個唯一的全局變量時遇到問題。我想在這裏做的是。Delphi:每個TIdcontext的唯一變量

TMyContext = class(TIdServerContext) 
    public 
    Tag: Integer; 
    Queue: TIdThreadSafeList; 
    FPacketBuffer: Pointer; 
    PacketBufferPtr: Integer; 

    constructor Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TThreadList = nil); override; 
    destructor Destroy; override; 
    end; 

,然後訪問使用TMyContext(AContext).FPacketBuffer變量,但我得到訪問衝突錯誤時,有一個連接活性和新的連接嘗試連接。這裏是什麼在我的idTcpConnect和idTcpDisconnect

procedure TMainFrm.MainSckConnect(AContext: TIdContext); 
begin 
    TMyContext(AContext).Queue.Clear; 
    TMyContext(AContext).Tag := -1; 
    GetMem(TMyContext(AContext).FPacketBuffer,65536); 
end; 

procedure TMainFrm.MainSckDisconnect(AContext: TIdContext); 
Var Client: TClientInfo; 
begin 
//If TMyContext(AContext).Queue.Count > 0 Then TMyContext(AContext).Queue.Clear; 
TMyContext(AContext).Queue.Clear; 
FreeMem(TMyContext(AContext).FPacketBuffer); 
If AContext.Data <> nil Then Begin 
    Client := Pointer(AContext.Data); 
    Clients.Remove(Client); 
    Client.Free; 
    AContext.Data := nil; 
End; 
end; 

錯誤occures時GetMem函數被調用idtcpconnect,我覺得我做的一切都是錯的,我不知道我怎麼可以有一個獨特的全局變量爲每個上下文。

+2

在連接回調中,實際上是AContext類型的TMyContext嗎?如果沒有,它將不會爲你的FPacketBuffer字段分配空間,這會炸掉。 –

+0

TMyContext是一類tidservercontext –

+0

是的,我可以看到,但是當MainSckConnect被調用時,它已被預先攔截,以便分配TMyConnect而不是常規的TIdContext。投射到TMyConnect不會奇蹟般地改變類型 - 它只是告訴編譯器假定它是一個TMyConnect實例。 –

回答

5

確保在運行時激活服務器,然後在指定的類類型的TIdTCPServer.ContextClass屬性,如:

procedure TMainFrm.FormCreate(Sender: TObject); 
begin 
    MainSck.ContextClass := TMyContext; 
end; 
+0

是在激活服務器之前分配的。我不知道爲什麼,但第一個客戶端沒有連接問題,但如果已經有連接並且FPacketbuffer未被釋放,那麼新連接會導致一個erorr,這是不是意味着該變量對每個上下文都不是唯一的?如果客戶端連接並斷開連接,則不存在問題,但如果之前已經有連接,則會生成錯誤。 –

+2

我向你保證,每個TIdContext對象都是唯一的,因此它的數據成員對於每個連接的客戶端都是唯一的。所以,其他的代碼可能在你還沒有顯示的代碼中出錯,你的客戶代碼只是環境的受害者。例如,如果你的'Clients'列表不是線程安全的並且正在破壞內存。 –

2

不能在類[已創建]對象實例更改爲不同類型。對象是在創建時實例化的類的

您可以安全地將任何對象轉換爲其自己的類或其繼承的任何類,因爲該類的對象是IS。在硬鑄鐵(像你這樣做),你告訴你知道你在做什麼,編譯器,例如:

type 
    TMyButton: TButton 
    public 
    FMyField: array[1..50] of byte; 
    end; 

var 
    Button: TButton; 
begin 
    //next line is valid, a variable of type TButton can reference any object 
    //inheriting from TButton or a TButton instance directly 
    Button := TMyButton.Create(nil); 
    //next line contains a valid cast, because Button contains a reference to 
    //a instance of TMyButton 
    TMyButton(Button).FMyField[10] := 5; 
    //valid, a TButton variable referencing a TButton instance 
    Button := TButton.Create(nil); 
    //next line is invalid and may cause an AV or in the worst case 
    //you may corrupt memory by doing that 
    TMyButton(AButton).FMyField[20] := 5; 
end; 

的事實是,在你的onConnect事件,你會得到一個已經創建TIdContext的實例(或後代類型)。

如果你想讓這個對象屬於你的類,你必須首先要求服務器通過ContextClass屬性創建該類的對象。您必須在服務器的Active屬性設置爲true之前執行此操作。

procedure TMyForm.Init; 
begin 
    MyServer.ContextClass := TMyContext; 
    MyServer.Active := True; 
end; 

最後,如果你有對象引用,你必須對上下文構造創建對象,或添加後期製作機構,如果你不想浪費內存,你不要太用它經常:

TMyContext = class(TIdServerContext) 
private 
    FQueue: TIdThreadSafeList; 
public 
    constructor Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TThreadList = nil); override; 
    destructor Destroy; override; 
    property Queue: TIdThreadSafeList read FQueue; 
end; 

constructor TMyContext.Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TThreadList = nil); 
begin 
    inherited; 
    FQueue := TIdThreadSafeList.Create(Parameters); 
end; 

destructor TMyContext.Destroy; 
begin 
    FQueue.Free; 
    inherited; 
end; 
0

PHEWWWW!我在想自己的錯在什麼地方,我在想每個連接的FPacetBuffer變量都不是唯一的,但是經過大量調試和註釋掉代碼段後,我發現問題並且我喜歡WHATTT!

在處理一個登錄包數據時,我聲明瞭一個PChar變量,並使用StrLCopy將數據複製到它並檢索了數據的大小,然後爲其分配了一個空字符(這是問題行)。

Size := (Packet.BufferSize-SizeOf(TLoginPacket)); 
GetMem(UserName,Size); 
StrLCopy(UserName, PChar(Cardinal(Packet)+SizeOf(TLoginPacket)),Size); 
UserName[Size] := #0; <--- This Line here 

大小變量保持實際大小+2。

感謝所有幫助球員:)