2

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 が呼び出されるとエラーが発生します。すべて間違っていると思います。コンテキストごとに一意のグローバル変数を設定する方法がわかりません。

4

3 に答える 3

5

TIdTCPServer.ContextClass実行時にサーバーをアクティブ化する前に、クラス タイプをプロパティに割り当てていることを確認してください。

procedure TMainFrm.FormCreate(Sender: TObject);
begin
  MainSck.ContextClass := TMyContext;
end;
于 2013-01-19T00:30:56.633 に答える
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 create メカニズムを追加する必要があります。

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;
于 2013-01-19T00:32:13.397 に答える
0

ふぅ!FPacetBuffer変数は各接続に固有のものではないと考えていましたが、多くのデバッグとコードセクションのコメントアウトの後、問題を発見し、WHATTTのようになりました!!!!

ログインパケットデータを処理する際に、PChar変数を宣言し、StrLCopyを使用してデータをコピーし、データのサイズを取得してから、自分でnull文字を割り当てました(これが問題の行でした)。

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

サイズ変数には、実際のサイズ + 2 が保持されていました。

すべての助けてくれてありがとう:)

于 2013-01-19T02:23:44.127 に答える