Delphi:每个TIdcontext的唯一变量

时间:2013-01-18 23:57:43

标签: delphi variables indy10

我遇到了为IdTCPServer的每个连接声明一个唯一全局变量的问题。我想在这里做的是。

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;

在idtcpconnect中调用getmem时发生错误,我想我做错了,我不知道如何为每个上下文创建一个唯一的全局变量。

3 个答案:

答案 0 :(得分:5)

确保在运行时激活服务器之前将类类型分配给TIdTCPServer.ContextClass属性,例如:

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

答案 1 :(得分: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;

最后,如果您有对象引用,则必须在上下文构造函数中创建对象,或者如果您不想浪费内存并且不经常使用它,则添加Late创建机制:

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;

答案 2 :(得分:0)

PHEWWWW!我正在自杀是什么问题,我认为FPacetBuffer变量并不是每个连接都是唯一的,但经过很多调试和注释掉代码部分之后,我看到了问题,我就像是什么!!!!

在处理登录数据包时,我声明了一个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。

感谢所有帮助人员:)