1

TCPServer および TCPClient コンポーネントを使用して相互に通信する 2 つのアプリケーションがあります。サーバーは非表示モードで起動します。Application.ShowMainForm: = false;

システムトレイのアイコンだけがユーザーと対話します。サーバーを実行した後、クライアントを実行してサーバーに接続するとフリーズしますが、サーバープロパティApplication.ShowMainFormtrueに変更すると、 すべてが完全に機能します。これは私が使用しているコードです:

クライアント アプリ:

procedure TFormCliente.FormCreate(Sender: TObject);
begin
  try
    cliente.Connect;
  except
    hint1.ActivateHint(FormCliente,'Error.' + #13 +
     'Verify if server is running','VCall',5000); //hint1 is a Jed component
  end;
end;

サーバーアプリ:

[...]
private
  FConexoes: TList;
[...]


type
  PClient   = ^TClient;
  TClient   = record
    PeerIP      : string[15];            { Client IP address }
    HostName    : String[40];            { Hostname }
    Connected,                           { Time of connect }
    LastAction  : TDateTime;             { Time of last transaction }
    AContext      : Pointer;             { Pointer to thread }
  end;
[...]

procedure TfrmServer.FormCreate(Sender: TObject);
begin
  FConexoes := TList.Create;
end;

procedure TFrmServer.FormDestroy(Sender: TObject);
begin
  FConexoes.Free;
end;

procedure TFrmServer.IdTCPServer1Connect(AContext: TIdContext);
var
  NewClient: PClient; 
begin
  GetMem(NewClient, SizeOf(TClient));
  NewClient.PeerIP      := AContext.Connection.Socket.Binding.PeerIP;
  NewClient.HostName    := GStack.HostByAddress(NewClient.PeerIP);
  NewClient.Connected   := Now;
  NewClient.LastAction  := NewClient.Connected;
  NewClient.AContext    := AContext;
  AContext.Data         := TObject(NewClient);
  ListView1.Items.Add.Caption:=NewClient.HostName;
end;

サーバーフォームが表示されている場合、クライアントのホスト名がリストビューに追加されますが、サーバーフォームが表示されていない場合、クライアントを実行して接続すると、クライアントプロセスを強制終了するまでサーバーがフリーズします。誰でも私を助けることができますか?

4

1 に答える 1

1

TListViewイベントでの直接アクセスは、OnConnectスレッドセーフではありません。それ自体がデッドロックやクラッシュを引き起こす可能性があります。代わりにこれを試してください:

type
  PClient   = ^TClient;
  TClient   = record
    PeerIP      : string;                { Client IP address }
    HostName    : String;                { Hostname }
    Connected,                           { Time of connect }
    LastAction  : TDateTime;             { Time of last transaction }
    AContext    : Pointer;               { Pointer to thread }
  end;

procedure TFrmServer.IdTCPServer1Connect(AContext: TIdContext);
var
  Client: PClient; 
begin
  New(Client);
  try
    Client.PeerIP      := AContext.Connection.Socket.Binding.PeerIP;
    Client.HostName    := GStack.HostByAddress(Client.PeerIP);
    Client.Connected   := Now;
    Client.LastAction  := Client.Connected;
    Client.AContext    := AContext;

    TThread.Synchronize(nil,
      procedure
      var
        Item: TListItem;
      begin
        Item := ListView1.Items.Add;
        Item.Data := Client;
        Item.Caption := Client.HostName;
      end
    );
  except
    Dispose(Client);
    raise;
  end;

  AContext.Data := TObject(Client);
end;

procedure TFrmServer.IdTCPServer1Disconnect(AContext: TIdContext);
var
  Client: PClient; 
begin
  Client := PClient(AContext.Data); 
  AContext.Data := nil;

  if Client = nil then Exit;

  TThread.Synchronize(nil,
    procedure
    var
      Item: TListItem;
    begin
      Item := ListView1.FindData(0, Client, True, False);
      if Item <> nil then
        Item.Delete;
    end
  );

  Dispose(NewClient);
end;
于 2013-06-17T21:44:53.037 に答える