Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi Indy TCP客户端/服务器,客户端充当服务器_Delphi_Client Server_Delphi Xe_Indy_Indy10 - Fatal编程技术网

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

Delphi Indy TCP客户端/服务器,客户端充当服务器,delphi,client-server,delphi-xe,indy,indy10,Delphi,Client Server,Delphi Xe,Indy,Indy10,Indy的TIdTCPClient和TIdTCPServer如何在以下场景中使用: Client ---------- initate connection -----------> Server ... Client <---------------command------------------- Server Client ----------------response-----------------> Server ... Client <-----

Indy的
TIdTCPClient
TIdTCPServer
如何在以下场景中使用:

Client  ---------- initate connection -----------> Server
...
Client  <---------------command------------------- Server
Client  ----------------response-----------------> Server
...
Client  <---------------command------------------- Server
Client  ----------------response-----------------> Server
客户端------------初始化连接------------>服务器
...
客户端服务器
...
客户端服务器
客户端启动连接,但充当“服务器”(等待命令并执行它们)

在这种情况下,
TIdTCPServer
OnExecute
方法不起作用(至少我没有让它起作用)。我怎么能这样做


我希望问题足够清楚。

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

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


希望这有帮助

对于Indy,这在设计上是不可能的:
Indy仅支持客户端发起的通信,这意味着服务器只能对客户端的请求发送响应。
获取所需内容的最简单方法(但不是最聪明的)是使用拉动过程。由计时器控制,客户端询问服务器是否有新命令。当然,这将导致大量的通信开销,并且根据您的拉入间隔,会有延迟。

或者,您可以使用另一个库,如ICS()

通常,客户端和服务器端都有一个线程来读取传入的电报,并发送挂起的电报……但是这种协议(发送/接收、何时和什么)取决于应用程序。

没有任何东西可以阻止您使用Indy的TIdTCPServer组件执行此操作

TIdTCPServer仅设置连接。您需要实现其余的功能。因此,实际发送和接收的顺序可以是您想要的任何顺序

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

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
以下是输出:

你叫什么名字

马库斯

你好,马库斯

你想玩个游戏吗

与主机的连接丢失

你没有电话网吗?这里有一些方法

或者使用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语句要等到有数据时才执行。这就是它背后的魔力。

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

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


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

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

是,此解决方案允许这样做!服务器只需要存储每个客户机的连接,这样它就可以直接向一个或多个客户机传递消息或命令,而不局限于首先响应客户机命令!如果客户端没有侦听线程,客户端如何知道它收到了一个命令?客户端与服务器有一个持久连接,因此客户端当然有一个侦听线程;)应该指出的是,我以前(反复)使用过双向通信的客户机/服务器系统。也许您可以使用
IdTCPClient1.IOHandler.ReadLnWait
IdTCPClient1.IOHandler.WaitFor
方法来模拟这种行为。否则,使用
TIdCmdTCPCLient
可以解决您的问题。目前,我正在使用Delphi 2010中的Indy 10。好问题,许多人需要在没有任何请求的情况下从服务器获取数据(以减少通信量),特别是当接收器位于NAT后面时,如果可能的话,它将成为使用TCP的单向穿孔(世界上还没有人在TCP打孔方面取得成功)。这真的是印地的设计缺陷吗?我一直认为这是TCP限制……哦,如果是这样的话,我想我们就像《不可能的任务》中的汤姆·克鲁斯一样因为在没有任何来自客户机的拉动的情况下,我们的服务器正在向我们的客户机发送消息,例如,当服务器关闭时,或者告诉所有连接的客户机某些数据的更改…IIUC TCP/IP通信是:1.客户机连接到服务器(根据定义,发起连接的一方就是客户机),2.双方可以随时发送数据(因为TCP/IP套接字是双向的)这根本不是一个限制。服务器可以随时向客户端发送数据,并且非常欢迎客户端检查传入的数据。Indy非常有能力。可能需要一段时间来了解它的所有内容,但它可以做到所有这些,然后再做一些。应该将“魔力”放在自己的线程中,以便应用程序能够在服务器无需说明的情况下继续。我以前实现过类似的协议,并成功地基于telnet客户端代码实现了该协议。