简体   繁体   English

如何使用Indy建立双向TCP连接?

[英]How to make a bidirectional TCP connection using Indy?

I use TIdTCPClient and TIdTCPServer (with my own protocol) and I want to make a TCP connection in which both computers can send commands and read replays. 我使用TIdTCPClientTIdTCPServer (具有自己的协议),并且希望建立TCP连接,两台计算机都可以在其中发送命令并读取重放。 Of course, one will be server and the other client, but just until the connection is established, after that, they both must be "servers and clients". 当然,一个将是服务器,另一个将是客户端,但是直到建立连接之前,它们都必须是“服务器和客户端”。 I don't know how to explain this more clearly... Mainly, computer "A" will send commands to computer "B", but sometimes, some events happen on the computer "B" and must be communicated immediately to computer "A". 我不知道如何更清楚地解释这一点...主要是,计算机“ A”将向计算机“ B”发送命令,但是有时,某些事件发生在计算机“ B”上,必须立即传达给计算机“ A” ”。 So, every computer should listen all the time for commands, but in the same time it must be able to send some commands when the events are happening. 因此,每台计算机都应该一直监听命令,但是同时,当事件发生时,它必须能够发送一些命令。

For sending commands it's simple: just write something to the socket. 发送命令很简单:只需向套接字写入内容即可。 But to be able to replay them, the application must read from socket, and if it read, it can't write.... I searched the internet and I found here and here some answers to similar questions, in which is said that should be used 2 threads, one for writing and one for reading. 但是为了能够重放它们,应用程序必须从套接字读取,如果读取,则无法编写...。我在互联网上搜索,发现在这里这里都找到类似问题的一些答案,据说应该使用2个线程,一个用于写入,一个用于读取。 But I don't understand how cand I use the same object, the connection socket, in 2 threads... What if one thread reads something that is changed by the other (the basic thread problem) ? 但是我不明白如何在2个线程中使用同一个对象(连接套接字)...如果一个线程读取了另一个更改的内容(基本线程问题)怎么办?

I have made some tests with a chat application with the following code and it seems it's working fine but I'm not sure if this is the correct way to do it... I mean, to create a connection and after that pass the socket object to two threads, one for read and one for write. 我已经使用下面的代码对聊天应用程序进行了一些测试,看来它工作正常,但是我不确定这是否是正确的方法...我的意思是,创建一个连接,然后通过套接字对象指向两个线程,一个用于读取,一个用于写入。

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;

computer "A" will send commands to computer "B", but sometimes, some events happen on the computer "B" and must be communicated immediately to computer "A". 计算机“ A”将向计算机“ B”发送命令,但有时某些事件在计算机“ B”上发生,必须立即传达给计算机“ A”。 So, every computer should listen all the time for commands, but in the same time it must be able to send some commands when the events are happening. 因此,每台计算机都应该一直监听命令,但是同时,当事件发生时,它必须能够发送一些命令。

When A sends a command to B, or vice versa, it has no way of knowing whether the next message received will be a response to the command or an unsolicited event. 当A向B发送命令时(反之亦然),它无法知道接收到的下一条消息是对命令的响应还是不请自来的事件。 So it can't just send a command and sit waiting for the response, as it may receive other messages in the meantime. 因此,它不能只是发送命令并等待响应,因为它同时可能会收到其他消息。 You will have to read messages asynchronously and handle them on a per-message basis as they arrive. 您将不得不异步读取消息,并在消息到达时以每个消息为基础对其进行处理。

To help facilitate this, every message must identify what it is (command, response, or event). 为了帮助实现此目的,每条消息都必须标识它是什么(命令,响应或事件)。 When a command is sent, the sender should include a user-defined value in it that is echoed back in the response. 发送命令时,发送方应在其中包含用户定义的值,该值将在响应中回显。 This will allow the sender to correlate response to commands, and even to have multiple commands in flight at the same time. 这将使发送方可以将响应与命令相关联,甚至可以同时运行多个命令。 Unsolicited events would not have a user-defined value in them, as they don't get a response. 不请自来的事件中将没有用户定义的值,因为它们不会得到响应。

This way, events can then be sent at any time, and when a command is received it can be processed in parallel to anything else, and a response sent back whenever it is ready (even out of order of other commands, if desired). 这样,便可以在任何时间发送事件,并且在接收到命令时可以并行处理其他事件,并在准备就绪时将响应发送回去(即使需要,也可以不按其他命令的顺序发送)。

For sending commands it's simple: just write something to the socket. 发送命令很简单:只需向套接字写入内容即可。 But to be able to replay them, the application must read from socket, and if it read, it can't write.... 但是为了能够重播它们,应用程序必须从套接字读取,并且如果读取,则无法写入...。

Yes, it can. 是的,它可以。 You just can't do it in the same thread, if the thread is blocked doing other things. 如果该线程被阻止执行其他操作,则无法在同一线程中执行此操作。

I searched the internet and I found here and here some answers to similar questions, in which is said that should be used 2 threads, one for writing and one for reading. 我搜索了互联网,然后在这里这里找到类似问题的一些答案,据说应该使用2个线程,一个用于写作,一个用于阅读。

Yes, that is one solution, and the one you will likely end up using with Indy, given its blocking nature. 是的,这是一种解决方案,考虑到它的阻塞性,您可能最终将其与Indy一起使用。 But it is not the only solution when working with sockets in general, there are better solutions (overlapped I/O, etc). 但这不是通常使用套接字的唯一解决方案,而是更好的解决方案(重叠的I / O等)。

But I don't understand how cand I use the same object, the connection socket, in 2 threads... 但是我不明白如何在2个线程中使用同一个对象(连接套接字)...

What makes you think it can't be shared? 是什么让您认为它无法共享? A socket has separate inbound and outbound buffers. 套接字具有单独的入站和出站缓冲区。 One thread can be reading inbound data while another thread is writing outbound data at the same time. 一个线程可以读取入站数据,而另一个线程可以同时写入出站数据。 They will not interfere with each other. 他们不会互相干扰。

What if one thread reads something that is changed by the other (the basic thread problem) ? 如果一个线程读取了另一线程更改的内容(基本线程问题)怎么办?

Nothing is being changed on the reading side while the writing side is working, and vice versa. 在写入端工作时,读取端没有任何更改,反之亦然。

What you have to watch out for is multiple threads reading from the socket at the same time, or multiple threads writing to the socket at the same time. 您需要注意的是多个线程同时从套接字读取,或者多个线程同时写入套接字。 That is not safe without adequate synchronization between the threads. 如果线程之间没有足够的同步,那是不安全的。 But one thread reading while one thread is writing is perfectly safe without synchronizing the two threads. 但是,在不同步两个线程的情况下,在写一个线程的同时读取一个线程是绝对安全的。

I have made some tests with a chat application with the following code and it seems it's working fine but I'm not sure if this is the correct way to do it... I mean, to create a connection and after that pass the socket object to two threads, one for read and one for write. 我已经使用下面的代码对聊天应用程序进行了一些测试,看来它工作正常,但是我不确定这是否是正确的方法...我的意思是,创建一个连接,然后通过套接字对象指向两个线程,一个用于读取,一个用于写入。

That is perfectly fine. 很好。 Just make sure the reading thread is terminated before the connection object is destroyed. 只要确保在连接对象销毁之前读取线程已终止即可。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM