Когда работаем с компонентом TServerSocket, мы можем использовать свойство Data для хранения указателя на класс, например, для каждого клиента. В случае использования Indy компонента TIdCmdTCPServer возникает вопрос: существует ли аналогичное свойство?
Решение проблемы
Да, такое свойство существует – это TIdContext.Data. В событиях TIdCmdTCPServer, которые передают параметр TIdCommand, доступ к объекту TIdContext можно получить через свойство TIdCommand.Context. Например:
type
TMyClass = class
// Добавьте необходимые поля...
end;
procedure TForm1.IdCmdTCPServer1Connect(AContext: TIdContext);
var
MyCls: TMyClass;
begin
MyCls := TMyClass.Create;
// Инициализируйте MyCls по необходимости...
AContext.Data := MyCls;
end;
procedure TForm1.IdCmdTCPServer1Disconnect(AContext: TIdContext);
begin
AContext.Data.Free;
AContext.Data := nil;
end;
procedure TForm1.IdCmdTCPServer1CommandHandlerCommand(ACommand: TIdCommand);
var
MyCls: TMyClass;
begin
MyCls := TMyClass(ACommand.Context.Data);
// Используйте MyCls по необходимости...
end;
Indy также предоставляет возможность создания пользовательского класса, унаследованного от TIdServerContext, с добавлением необходимых полей и присвоением его свойству ContextClass сервера перед его активацией. Это позволит вам использовать типизацию к вашему классу при работе с контекстом:
type
TMyContext = class(TIdServerContext)
public
// Добавьте необходимые поля...
constructor Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TIdContextThreadList = nil); override;
destructor Destroy; override;
end;
constructor TMyContext.Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TIdContextThreadList = nil);
begin
inherited;
//...
end;
destructor TMyContext.Destroy;
begin
//...
inherited;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
IdCmdTCPServer1.ContextClass := TMyContext;
end;
procedure TForm1.IdCmdTCPServer1Connect(AContext: TIdContext);
var
MyCtx: TMyContext;
begin
MyCtx := TMyContext(AContext);
// Инициализируйте MyCtx по необходимости...
end;
procedure TForm1.IdCmdTCPServer1CommandHandlerCommand(ACommand: TIdCommand);
var
MyCtx: TMyContext;
begin
MyCtx := TMyContext(ACommand.Context);
// Используйте MyCtx по необходимости...
end;
Это позволяет избежать необходимости выделения памяти под отдельные классы для каждого клиента, используя то, что сервер создает для вас.
Альтернативный способ доступа к клиентам
Если вам нужно обращаться к клиентам вне событий сервера, можно использовать следующий подход:
var
List: TIdContextThreadList;
MyCls: TMyClass;
begin
List := IdCmdTCPServer1.Contexts.LockList;
try
MyCls := TMyClass(TIdContext(List[index]).Data);
// Используйте MyCls по необходимости
finally
IdCmdTCPServer1.Contexts.UnlockList;
end;
Это не рекомендуемый способ, так как лучше обращаться к клиентам внутри событий сервера.
Пример использования в реальном приложении
Пример использования, описанного выше, подходит для реализации механизма обмена сообщениями между клиентами через ваш сервер. Например, если у вас есть приложение на Android и устройство GPRS, которые оба подключаются к вашему серверу, и вы хотите, чтобы одно отправило сообщение другому, вы можете использовать описанные механизмы для реализации этой функции.
В контексте обсуждается использование свойства `Data` для хранения указателей на классы в компоненте `TIdCmdTCPServer` Indy, аналогично тому, как это делается в компоненте `TServerSocket`.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.