Delphi Indy TCP客户端/服务器,客户端充当服务器
Indy的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 <-----
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客户端代码实现了该协议。