Indy TCP 客户端/服务器,客户端充当服务器

发布于 2024-12-20 03:26:26 字数 591 浏览 8 评论 0原文

Indy 的 TIdTCPClientTIdTCPServer 可以用于以下场景:

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

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

在这种情况下,TIdTCPServerOnExecute 方法不能很好地工作(至少我没有让它很好地工作)。我怎么能这样做呢?

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

How can Indy's TIdTCPClient and TIdTCPServer be used in the following scenario:

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

The client initiates the connection, but acts as a "server" (waiting for commands and executing them).

The OnExecute approach of TIdTCPServer does not work well in this case (at least I am not getting it to work well). How could I do this?

I hope the question is clear enough.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

习ぎ惯性依靠 2024-12-27 03:26:26

没有什么可以阻止您使用 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 语句会等待,直到有数据为止。这就是这一切背后的魔力。

There is nothing preventing you from doing this with Indy's TIdTCPServer component.

A TIdTCPServer only sets up the connection. You'll need to implement the rest. So the sequence of the actual sending and receiving can be whatever you want.

Put this code in your TIdTCPServer component's OnExecute event:

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;

Here's how you can setup the TIdTCPServer really simply:

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

This tells the server to listen on the loopback address only, at port 8080. This prevents anyone outside of your computer from connecting to it.

Then, to connect your client, you can go to a Windows command prompt and type the following:

telnet 127.0.0.1 8080

Here's the output:

What is your name?

Marcus

Hello, Marcus.

Would you like to play a game?

Connection to host lost.

Don't have telnet? Here's how to install telnet client on Vista and 7.

Or with a TIdTCP Client, you can do this:

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;

An important thing to note here is that the ReadLn statements wait until there is data. That's the magic behind it all.

不知在何时 2024-12-27 03:26:26

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

If your commands are textual in nature, then have a look at the TIdCmdTCPClient component, it is specifically designed for situations when the server is sending commands instead of the client. The server can use TIdContext.Connection.IOHandler.WriteLn() or TIdContext.Connection.IOHandler.SendCmd() to send the commands.

新雨望断虹 2024-12-27 03:26:26

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

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

希望这有帮助!

When the client connects to the server, the server has an OnConnect event with an AContext: TIdContext parameter.

A property of this is AContext.Connection, which you can store outside of that event (say, in an Array). If you pair it with the IP or better yet a generated Session ID, then reference that Connection by that criteria, you can then have the server send adhoc commands or messages to the client.

Hope this helps!

地狱即天堂 2024-12-27 03:26:26

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

normally the client and the server side have a thread that is reading incoming telegrams, and sending pending telegrams...but this kind of protocols (send/receive, when and what) depend of the application.

左耳近心 2024-12-27 03:26:26

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

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

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

A very good starting point how the client side can be implemented using a thread, listening for messages from the server, is the Indy Telnet client component (TIdTelnet in the Protocols folder).

The Indy telnet client connects to the telnet server and uses only one socket to write and read data. Reading happens in a listener thread.

This design can easily be adapted to build distributed messaging software like chat etc., and also shows how easy the protocol can be decoupled from the network layer using blocking sockets.

甜`诱少女 2024-12-27 03:26:26

对于 Indy,这在设计上是不可能的:
Indy 仅支持客户端发起的通信,这意味着服务器只能对客户端的请求发送响应。
获得你想要的东西的最简单的方法(但不是最聪明的)是使用拉过程。由计时器控制,客户端询问服务器是否有新命令。当然,这会导致大量的流量开销,并且根据您的拉动间隔,会有延迟。
或者,您可以使用其他库,例如 ICS (http://www.overbyte.be/eng/产品/ics.html

With Indy this is not possible by design:
Indy supports only Client-initiated communication, what means the server can only send a response to requests by the client.
The easiest way (but not the smartest) to get what you want is to use a pull-process. Controlled by a timer the clients ask the server if there is a new command. Of course this will cause a lot of traffic-overhead and depending on your pull-intervall there is a delay.
Alternatively you could use another library like ICS (http://www.overbyte.be/eng/products/ics.html)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文