2011-12-07 81 views
17

哪有Indy的TIdTCPClientTIdTCPServer在以下情况下使用:印TCP客户机/服务器

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

客户发起连接,但作为一个“服务器” (等待命令并执行它们)。

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

我希望问题很清楚。

+2

也许你可以用'IdTCPClient1.IOHandler.ReadLnWait'或'IdTCPClient1.IOHandler.WaitFor'方法来模拟这种行为。否则,使用'TIdCmdTCPCLient'可以解决你的问题。 – LightBulb

+0

哪个版本的Indy? –

+0

目前,我在德尔福2010年使用Indy 10。 – LightBulb

回答

17

没有什么能够阻止你使用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 

下面是输出:

你叫什么名字?

马库斯

你好,马库斯。

你想玩游戏吗?

与主机连接丢失。

没有telnet?以下是install telnet client on Vista and 7的操作方法。

或者用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陈述等到有数据。这是所有背后的魔力。

+7

'魔术'应该放在它自己的线程中,以便应用程序可以继续,而服务器无话可说 – mjn

5

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

此属性为AContext.Connection,您可以在该事件之外存储(例如,在数组中)。如果将它与IP配对,或者生成的会话ID更好,然后通过该条件引用Connection,则可以让服务器向客户端发送特定命令或消息。

希望这会有所帮助!

+0

他问客户端是否可以侦听来自服务器的命令。 – LightBulb

+2

是的,这个解决方案允许!服务器只需要存储每个客户端的连接,以便它可以将消息或命令直接传递给一个或多个客户端,而不必局限于首先响应客户端命令! – LaKraven

+0

如果客户端没有监听线程,客户如何知道它收到了一条命令? – LightBulb

-3

对于Indy,这是不可能的设计:
Indy只支持客户端发起的通信,这意味着服务器只能发送对客户端请求的响应。
最简单的方法(但不是最聪明的)得到你想要的就是使用拉过程。由定时器控制客户机询问服务器是否有新命令。当然,这会造成很大的流量开销,并且取决于你的拉间隔有一个延迟。
另外,您可以使用像ICS另一个库(http://www.overbyte.be/eng/products/ics.html

+1

这是Indy的设计缺陷吗?我一直认为这是一个TCP限制... –

+0

哦,在那种情况下,我想我们就像汤姆克鲁斯在“不可能的任务”,因为没有从我们的客户拉,我们的服务器发送消息给我们的客户,例如当它正在关闭,或者告诉所有连接的客户端某些数据发生变化...... –

+3

IIUC TCP/IP通信是:1.客户端连接到服务器(根据定义,发起连接的一方是客户端),2。双方可以随时发送数据(因为TCP/IP套接字是双向的) – mjn

4

通常在客户端和服务器端有一个线程正在读来电,并发送未决电报......但这种协议(发送/接收,何时何地)取决于应用程序。

3

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

印地远程登录客户端连接到Telnet服务器,并使用只有一个插座读取数据。读取发生在一个监听器线程中。

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

+0

我已经实现了一个像这样的协议,并成功地将其基于telnet客户端代码。 – MikeT

6

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