我遇到了为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时发生错误,我想我做错了,我不知道如何为每个上下文创建一个唯一的全局变量。
答案 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。
感谢所有帮助人员:)