如何使用Indy进行双向TCP连接?

时间:2017-08-18 18:13:03

标签: multithreading sockets delphi tcp indy

我使用TIdTCPClientTIdTCPServer(使用我自己的协议)并且我想建立一个TCP连接,其中两台计算机都可以发送命令和读取重放。当然,一个是服务器而另一个是客户端,但是直到建立连接,之后,它们都必须是服务器和客户端"。我不知道如何更清楚地解释这一点......主要是计算机" A"将命令发送到计算机" B"但有时,某些事件发生在计算机上" B"并且必须立即通知计算机" A"。因此,每台计算机都应该一直监听命令,但同时它必须能够在事件发生时发送一些命令。

发送命令很简单:只需向套接字写一些内容即可。但是为了能够重放它们,应用程序必须从套接字读取,如果它读取,它就无法写入....我搜索了互联网,我发现herehere一些类似问题的答案,其中应该使用2个线程,一个用于写入,一个用于阅读。但我不明白我是如何使用相同的对象,连接套接字,在2个线程中...如果一个线程读取由另一个线程更改的内容(基本线程问题)怎么办?

我已经使用以下代码对聊天应用程序进行了一些测试,看起来它工作正常,但我不确定这是否是正确的方法...我的意思是,创建一个连接,然后将套接字对象传递给两个线程,一个用于读取,另一个用于写入。

constructor TReadingThread.Create(ASocket: TIdIOHandlerSocket);
begin
  FSocket := ASocket;
  inherited Create(False);
end;

procedure TReadingThread.Execute;
var
  cmd: string;
begin
  while not Terminated do
  begin
    cmd := FSocket.ReadLn;
    Trim(cmd);
    if cmd <> '' then
    Synchronize(
    procedure
    begin
      Form1.Display.Lines.Add(cmd);
    end);
  end;
end;

procedure TForm1.BConnectClick(Sender: TObject);
begin
 TCPClient.Connect;
end;

procedure TForm1.InputKeyPress(Sender: TObject; var Key: Char);
begin
 if Key=#13 then begin
  TCPClient.Socket.WriteLn(Input.Text);
  Input.Clear;
  Key:=#0;
 end;
end;

procedure TForm1.TCPClientConnected(Sender: TObject);
begin
 readthread:= TReadingThread.Create(TCPClient.Socket);
 Display.Lines.Add('Server: Connected.');
end;

1 个答案:

答案 0 :(得分:6)

  计算机&#34; A&#34;将命令发送到计算机&#34; B&#34;但有时,某些事件发生在计算机上&#34; B&#34;并且必须立即通知计算机&#34; A&#34;。因此,每台计算机都应该一直监听命令,但同时它必须能够在事件发生时发送一些命令。

当A向B发送命令时,反之亦然,它无法知道接收到的下一条消息是对命令的响应还是未经请求的事件。因此它不能发送命令并等待响应,因为它可能同时接收其他消息。您必须异步读取消息,并在它们到达时按消息处理它们。

为了帮助实现这一点,每条消息都必须识别它是什么(命令,响应或事件)。发送命令时,发件人应在其中包含一个用户定义的值,该值在响应中回显。这将允许发送者将响应与命令相关联,甚至允许同时在飞行中具有多个命令。未经请求的事件中没有用户定义的值,因为他们没有得到回复。

这样,事件就可以随时发送,并且当接收到命令时,它可以与其他任何内容并行处理,并且只要它准备好就会发回响应(即使其他命令的顺序不正确,如果需要)。

  

发送命令很简单:只需向套接字写一些内容即可。但是为了能够重放它们,应用程序必须从套接字读取,如果它读取,它就无法写入....

是的,它可以。如果线程被阻止做其他事情,你就不能在同一个线程中执行它。

  

我搜索了互联网,我找到了herehere类似问题的答案,其中说应该使用2个帖子,一个用于写作,一个用于阅读。

是的,这是一个解决方案,并且鉴于其阻塞特性,您可能最终会使用Indy。但是,通常使用套接字时,它不是唯一的解决方案,有更好的解决方案(重叠的I / O等)。

  

但是我不明白我是如何使用相同的对象,即2个线程中的连接套接字......

是什么让你认为它无法分享?套接字具有单独的入站和出站缓冲区。一个线程可以读取入站数据,而另一个线程同时写入出站数据。他们不会互相干扰。

  

如果一个线程读取由另一个线程更改的内容(基本线程问题)怎么办?

在写作方面工作时,阅读方面没有任何改变,反之亦然。

您需要注意的是同时从套接字读取多个线程,或者多个线程同时写入套接字。如果线程之间没有足够的同步,这是不安全的。但是,在一个线程正在写入时,一个线程读取是完全安全的,而不同步两个线程。

  

我已经使用以下代码对聊天应用程序进行了一些测试,看起来它工作正常,但我不确定这是否是正确的方法...我的意思是,创建一个连接,然后将套接字对象传递给两个线程,一个用于读取,另一个用于写入。

这很好。只需确保在连接对象被销毁之前终止读取线程。