20

Indy'sTIdTCPClient和如何TIdTCPServer在以下场景中使用:

Client  ---------- initate connection -----------> Server
...
Client  <---------------command------------------- Server
Client  ----------------response-----------------> Server
...
Client  <---------------command------------------- Server
Client  ----------------response-----------------> Server

客户端启动连接,但充当“服务器”(等待命令并执行它们)。

OnExecute方法TIdTCPServer在这种情况下效果不佳(至少我没有让它运作良好)。我怎么能这样做?

我希望这个问题足够清楚。

4

6 回答 6

20

没有什么可以阻止您使用 Indy 的 TIdTCPServer 组件执行此操作。

TIdTCPServer 仅设置连接。你需要实现其余的。所以实际发送和接收的顺序可以是任何你想要的。

将此代码放入您的 TIdTCPServer 组件的 OnExecute 事件中:

var
  sName: String;
begin
  // Send command to client immediately after connection
  AContext.Connection.Socket.WriteLn('What is your name?');
  // Receive response from client
  sName := AContext.Connection.Socket.ReadLn;
  // Send a response to the client
  AContext.Connection.Socket.WriteLn('Hello, ' + sName + '.');
  AContext.Connection.Socket.WriteLn('Would you like to play a game?');
  // We're done with our session
  AContext.Connection.Disconnect;
end;

以下是您可以非常简单地设置 TIdTCPServer 的方法:

IdTCPServer1.Bindings.Clear;
IdTCPServer1.Bindings.Add.SetBinding('127.0.0.1', 8080);
IdTCPServer1.Active := True;

这告诉服务器仅在端口 8080 上侦听环回地址。这可以防止计算机之外的任何人连接到它。

然后,要连接您的客户端,您可以转到 Windows 命令提示符并键入以下内容:

telnet 127.0.0.1 8080

这是输出:

你叫什么名字?

马库斯

你好,马库斯。

你想玩游戏吗?

与主机的连接丢失。

没有远程登录?这是在 Vista 和 7 上安装 telnet 客户端的方法。

或者使用 TIdTCP 客户端,您可以这样做:

var
  sPrompt: String;
  sResponse: String;
begin
  // Set port to connect to
  IdTCPClient1.Port := 8080;
  // Set host to connect to
  IdTCPClient1.Host := '127.0.0.1';
  // Now actually connect
  IdTCPClient1.Connect;
  // Read the prompt text from the server
  sPrompt := IdTCPClient1.Socket.ReadLn;
  // Show it to the user and ask the user to respond
  sResponse := InputBox('Prompt', sPrompt, '');
  // Send user's response back to server
  IdTCPClient1.Socket.WriteLn(sResponse);
  // Show the user the server's final message
  ShowMessage(IdTCPClient1.Socket.AllData);
end;

这里要注意的重要一点是,ReadLn 语句一直等到有数据。这就是这一切背后的魔力。

于 2011-12-07T15:20:25.747 回答
8

如果你的命令本质上是文本的,那么看看这个TIdCmdTCPClient组件,它是专门为服务器而不是客户端发送命令的情况而设计的。服务器可以使用TIdContext.Connection.IOHandler.WriteLn()TIdContext.Connection.IOHandler.SendCmd()发送命令。

于 2011-12-07T18:03:15.083 回答
5

当客户端连接到服务器时,服务器会有一个带AContext: TIdContext参数的 OnConnect 事件。

它的一个属性是AContext.Connection,您可以将其存储在该事件之外(例如,在一个数组中)。如果您将它与 IP 或更好的生成会话 ID 配对,然后通过该标准引用该连接,您可以让服务器向客户端发送临时命令或消息。

希望这可以帮助!

于 2011-12-07T13:32:14.320 回答
4

通常客户端和服务器端有一个线程正在读取传入的电报,并发送待处理的电报......但是这种协议(发送/接收,何时以及什么)取决于应用程序。

于 2011-12-07T14:08:57.283 回答
3

Indy Telnet 客户端组件(Protocols 文件夹中的 TIdTelnet)是一个很好的起点,如何使用线程实现客户端,监听来自服务器的消息。

Indy telnet 客户端连接到 telnet 服务器,并且只使用一个套接字来写入读取数据。读取发生在侦听器线程中。

这种设计可以很容易地适应构建分布式消息传递软件,如聊天等,并且还显示了使用阻塞套接字将协议与网络层分离是多么容易。

于 2011-12-07T16:54:17.860 回答
-3

对于 Indy,这在设计上是不可能的:
Indy 仅支持客户端发起的通信,这意味着服务器只能对客户端的请求发送响应。
获得所需内容的最简单方法(但不是最聪明的方法)是使用拉取过程。由计时器控制,客户端询问服务器是否有新命令。当然,这会导致大量的流量开销,并且根据您的 pull-intervall 会有延迟。
或者,您可以使用另一个库,如 ICS ( http://www.overbyte.be/eng/products/ics.html )

于 2011-12-07T14:06:20.600 回答