2

我有一个错误让我很困惑。以下代码将一行从 TidTCPClient 发送到 TidTCPServer。第一次执行时,它运行良好。它第二次执行,之后每次都在每个字符串的开头添加一个换行符。我错过了什么?(我知道它以一种奇怪的方式做到了,但完整代码中需要客户列表)

   procedure TClientForm.ButtonSendStringClick(Sender: TObject);
    var
      I: integer;
      List: TList;
    begin
      List := ClientList.LockList;
      try
       for I := 0 to (List.Count- 1) do
        begin
          TidTCPClient(List[I]).IOHandler.WriteLn('Hello'+'|x|');
        end;
      finally
       ClientList.UnlockList;
      end;
      Edit1.Text := '';
    end;

    procedure TClientForm.IdTCPServer1Execute(AContext: TIdContext);
    var
    LLine: string;
    begin
    LLine := Acontext.Connection.IOHandler.ReadLn('|x|');
    OutputDebugString(PChar(LLine));
    end;
4

2 回答 2

3

WriteLn()将 CRLF 附加到您传递给它的字符串的末尾,但ReadLn()在遇到您指定的终止符字符串时停止读取。所以你正在发送'Hello|x|#13#10',但你只是在阅读'Hello|x|',留#13#10在套接字缓冲区中以供下一次读取。

要解决您的问题,您有两种选择:

1) 如果您想在 中继续使用自定义终止符ReadLn(),请更改WriteLn()Write()不再发送隐式 CRLF。您的通话无需更改ReadLn()

Write('Hello|x|');
LLine := ReadLn('|x|');

2) 完全停止使用自定义终结器。仅将您的主字符串传递给WriteLn()它并让它附加一个 CRLF,然后不要将任何终止符传递给它,ReadLn()因为它的默认终止符是 LF(包括对 CRLF 的处理)。

WriteLn('Hello');
LLine := ReadLn();
于 2012-04-16T15:25:50.847 回答
2

我在您的客户端代码中发现了一个潜在问题,ClientList.unlocklist应该在您的循环之外执行:

procedure TClientForm.ButtonSendStringClick(Sender: TObject);
var
  I: integer;
  List      : TList; 
begin     
  List := ClientList.LockList;
  try
   for I := 0 to (List.Count- 1) do
    begin
      ShowMessage('Text to encrypt is ' + Edit1.Text);
      TidTCPClient(List[I]).IOHandler.WriteLn((Encrypt(Edit1.Text,'Pass')+'|x|'));      
    end;
  finally
   ClientList.UnlockList;
  end;
  Edit1.Text := '';
end;

不要在服务器的执行事件中使用 showmessage,因为这不是您必须使用synchronize或使用其他日志记录方法的主 GUI 线程。另一个潜在的问题是,您的加密字符串可能包含回车字符甚至空字符 (#0),在这种情况下Readln,您的服务器的方法将无法读取整个加密字符串,因此无法解密。解决此问题的一种方法是使用base64 encoding.

编辑

问题在于您使用的是 '|x|' 终止符与 ReadLn 结合使用。由于您从客户端使用 writeln,因此您可以执行此操作

procedure TClientForm.IdTCPServer1Execute(AContext: TIdContext);
var
 LLine: string;
begin
 LLine := Acontext.Connection.IOHandler.ReadLn;
 OutputDebugString(PChar(LLine));
end;

如果您想使用终结器,请不要使用writelnandreadln

于 2012-04-15T18:05:14.027 回答