我最近开始使用Indy 10(来自Delphi XE3)和TCP连接。在您的帮助下(特别感谢Remy Lebeau),我已经可以构建一个用于管理客户端连接的简单服务器应用程序(请参阅此处Delphi - Simple TCP client / server using Indy to check clients status)。我正在使用列表框添加连接的客户端。见代码:
procedure TfrmMain.TCPServerConnect(AContext: TIdContext);
var
Host: String;
begin
Host := UpperCase(GStack.HostByAddress(AContext.Binding.PeerIP));
TThread.Queue(nil,
Procedure
begin
ListBox.Itens.Add(Host);
Log('Connected - ' + Host);
With TCPServer.Contexts.LockList Do
Try
StatusBar.Panels[0].Text := 'Connected Clients: ' + IntToStr(Count);
Finally
TCPServer.Contexts.UnlockList;
end;
end
);
end;
现在我正在尝试发送"你好"从服务器到列表中的特定客户端。我的想法是单击以在列表框中选择客户端主机名,然后单击按钮发送消息。但我正在研究的是事情并不像我想的那么容易......
拜托,一些Indy专家可以指出正确的方向(使用Indy 10)吗?
谢谢!
答案 0 :(得分:2)
最常从OnConnect
事件发送问候语,您可以直接访问已连接的客户端的TIdContext
。
话虽如此,如果您想从服务器事件外部向特定客户端发送数据,那么您需要跟踪所需客户端的TIdContext
对象,或者在服务器中查找它#39; s Contexts
列表。在此特定示例中,您可以将TIdContext
对象指针存储在ListBox本身中,然后在需要时检索它,例如:
procedure TfrmMain.TCPServerConnect(AContext: TIdContext);
var
Host: String;
begin
Host := UpperCase(GStack.HostByAddress(AContext.Binding.PeerIP));
TThread.Queue(nil,
procedure
begin
ListBox.Items.AddObject(Host, AContext);
Log('Connected - ' + Host);
With TCPServer.Contexts.LockList Do
Try
StatusBar.Panels[0].Text := 'Connected Clients: ' + IntToStr(Count);
Finally
TCPServer.Contexts.UnlockList;
end;
end
);
end;
procedure TfrmMain.TCPServerDisconnect(AContext: TIdContext);
var
Host: String;
begin
Host := UpperCase(GStack.HostByAddress(AContext.Binding.PeerIP));
TThread.Queue(nil,
procedure
var
Index: Integer;
begin
Index := ListBox.Items.IndexOfObject(AContext);
if Index <> -1 then
ListBox.Items.Delete(Index);
Log('Disconnected - ' + Host);
With TCPServer.Contexts.LockList Do
Try
StatusBar.Panels[0].Text := 'Connected Clients: ' + IntToStr(Count);
Finally
TCPServer.Contexts.UnlockList;
end;
end
);
end;
procedure TfrmMain.sendButtonClick(Sender: TObject);
var
Index: Integer;
Ctx: TIdContext;
begin
Index := ListBox.ItemIndex;
if Index = -1 then Exit;
Context := TIdContext(ListBox.Items.Objects[Index]);
// use Context as needed...
end;
当然,这不是最安全的方法,但它会让你开始。你需要考虑的事情:
客户端可能会断开并释放其TIdContext
对象,然后再将其从ListBox中删除。在使用之前,您应确保该对象仍在服务器的Contexts
列表中。
从按钮事件(或任何其他非服务器事件)发送未经请求的数据不是线程安全的。如果您从其他线程向同一客户端发送数据,特别是从服务器的事件发送数据,而不同步线程,则通信可能会损坏。您应仅在服务器事件中管理通信。如果需要从事件外部发送数据,将数据放入每个客户端的线程安全队列更安全,然后让OnExecute
事件在安全的情况下发送队列内容所以。我之前已经在几个不同的论坛上发布了很多次的例子,所以在网上找到它们应该不难。
OnDisconnect
事件不是查找客户端详细信息的好地方,例如其主机名。您应该在OnConnect
和/或OnExecute
事件中执行此操作,然后缓存该值以供以后使用。您可以将TIdContext.Data
属性用于此目的,或从TIdServerContext
派生新类并在激活服务器之前设置服务器的ContextClass
属性。