【问题标题】:idTCPServer sending message to idTCPClient without client activityidTCPServer 在没有客户端活动的情况下向 idTCPClient 发送消息
【发布时间】:2016-05-14 09:44:02
【问题描述】:

我正在使用 Embarcadero C++ Builder,我知道如何打开连接并等待来自服务器端的响应(客户端可以打开连接、发送消息并读取从服务器发送的消息,直到连接关闭)。

客户端:

IdTCPClient1->Connect();
IdTCPClient1->Socket->WriteLn("message from client");
ShowMessage(IdTCPClient1->Socket->ReadLn());
IdTCPClient1->Disconnect();

服务器端:

ShowMessage(AContext->Connection->Socket->ReadLn());    
AContext->Connection->Socket->WriteLn("Message from server");
AContext->Connection->Disconnect();

如果客户端在客户端打开连接,现在可以交换消息,但是我需要服务器向所有用户发送消息,这意味着客户端将不知道何时打开连接。我想我正在寻找一些等待服务器消息的事件。我发现的所有示例都在 Delphi 中,而不是 C++。另外,当每个客户端第一次连接时,我创建了一个vector<TIdContext*> 来保存所有连接,效果很好。

【问题讨论】:

  • 如果您未连接,则无法发送消息。为什么不连接,然后保持连接打开,这样双方就可以发送消息,而不是立即断开连接?
  • @immibis,为什么?当然,您可以在未连接的套接字上发送消息。只是不是 TCP 消息。
  • 看起来 TCP 不是最适合您的传输方式。使用 UDP 可能会更好。
  • @SergeyA TCP 在这里是完全合理的。
  • @immibis,因为何时通过单播向多个客户端发送相同的消息是合理的?

标签: c++ c++builder indy


【解决方案1】:

这是一个如何从 TIdTCPServer 向所有连接的客户端发送消息的示例:

TIdContext *MyContext;
TList *ClientsList = IdTCPServer1->Contexts->LockList();
try {
    for (int i = 0; i < ClientsList->Count; i++) {
        MyContext = (TIdContext*) ClientsList->Items[i];
        MyContext->Connection->IOHandler->WriteLn("Message for all the clients");
    }
__finally {
    IdTCPServer1->Contexts->UnlockList();
}

【讨论】:

  • 我应该在客户端的哪个位置从服务器读取消息?它是一些内置事件吗?当我知道服务器将发送消息时,我只是等待消息,但是当服务器在没有客户端请求的情况下发送消息时,我真的不知道该怎么做。
  • 这是一个非常简单的例子。它不考虑协议。如果客户端正在发送命令,或者服务器正在发送响应怎么办? WriteLn() 会践踏任何正在发送的响应数据。 TIdTCPServer 是一个多线程组件,每个客户端都运行在自己的线程中,每个线程为各自的客户端处理套接字 I/O。使用LockList() 通常不会使代码线程安全...
  • 当服务器需要向客户端发送unsolicited消息时,你应该在@ 987654325@ 事件并在OnDisconnect 事件中释放它,然后上面的循环(在任何线程中)可以将新消息放入每个客户端的队列中,并让OnExecute 事件处理程序在实际发送队列的内容时发送当它不忙于做其他事情时,这样做是安全的。我之前已经在 StackOverflow、Embarcadero 论坛和 Indy 论坛上发布了该模型的 许多 示例。到处搜索。
  • 在客户端,当处理 unsolicited 消息时,客户端必须持续监视连接是否有新的入站消息,无论是在计时器还是在工作线程中更好。对此没有客户端事件。这也意味着您必须在该计时器/线程中完成所有的阅读,包括对发送到服务器的命令的响应。
  • 谢谢 Remy,我最终使用了线程,它就像我想要的那样工作。也感谢其他人的想法和建议。它实际上给我留下了深刻的印象,我在这里得到了有价值的答案。所以我想管理员可以锁定这个或任何程序。是的,再次感谢你们。干杯
【解决方案2】:

你说

...这意味着客户端将不知道何时打开连接。我想我正在寻找一些等待服务器消息的事件。

如果您想保持单个 TCP 连接,保持打开状态并监视消息,则上面的答案中有很多很好的选择。

评论中提到的另一个选项是(也)设置 UDP 连接。在您的每个“客户端”上,创建一个侦听特定端口的 iDUDPServer(将与您的 TCP 连接不同的端口)。在您的“服务器”上,创建一个 TIdUDPClient。 请注意此处的术语差异,您将在所谓的 TCP 客户端上安装 UDPServer,反之亦然

使用它从服务器向您的“客户端”发送一条 UDP 消息。您将在(客户端的)IdUDPServer OnUDPRead 事件中捕获该消息。

如果您的所有客户端都在同一个网段上,您可以使用 UDP 广播向所有正在监听的客户端发送一条消息。如果没有,请使用您的每个客户的 IP 地址向他们发送消息。

您的问题之一是缺少 C++ 示例。抱歉,我对 C++ 代码无能为力。这是伪代码/程序,您必须管理语言语法:

在你的“客户”上,

  1. 创建一个 TIdUDPServer(把它放在一个表单上,它必须可以监听)。

  2. 将 DefaultPort 设置为监听端口(如果您愿意,可以设置其他选项)

  3. 为 IdUDPServerUDPRead(AThread: TIdUDPListenerThread; 分配事件代码; AData:TArray;绑定:TIdSocketHandle)。传入的数据在 AData 中。如果您愿意,可以通过查看 ABinding.PeerIP 来确认源的 IP。

在你的“服务器”上

  1. 创建 TIdUPDClient。

  2. 通过以下方式将您的消息发送到特定 IP:

    a:设置 IdUDPClient.Host(目标)

    b:设置 IdUDPClient.Port(目标)

    c: IdUDPClient.Send(msg)

    或者,您可以通过以下方式向您网段上的所有人广播:

    a: IdUDPClient.Broadcast(msg,TargetPort)

  3. “msg”将在 IdUDPServerUDPRead 事件中作为 AData 参数显示在您的客户端上。

此选项可能稍微复杂一些,因为它涉及两个消息路径,但它不需要客户端打开与服务器的 TCP 连接,也不涉及为入站消息设置监控循环。事实上,如果客户端不知道要连接,它可以用来通告服务器的位置。此 UDP 通信是对现有 TCP 连接的补充,因此这些连接保持不变。

【讨论】:

    猜你喜欢
    • 2017-05-10
    • 1970-01-01
    • 2019-04-29
    • 2015-04-05
    • 1970-01-01
    • 1970-01-01
    • 2017-12-04
    • 2015-04-25
    相关资源
    最近更新 更多