Delphi 如何将多行TStrings数据从TIdTCPServer传递到TIdTCPClient

Delphi 如何将多行TStrings数据从TIdTCPServer传递到TIdTCPClient,delphi,unicode,delphi-xe3,indy10,tstringlist,Delphi,Unicode,Delphi Xe3,Indy10,Tstringlist,我试图将数据库记录从服务器端应用程序传递到客户端应用程序。在客户端,我需要将数据存储到TStrings集合中 当我传递一个多行字段时,我在客户端收到两个独立的数据项,而不是一个多行数据项!我也尝试使用基于Unicode UTF8的命令来实现这一点,但不幸的是结果是一样的 服务器端代码: procedure TForm1.IdCmdTCPServer1CommandHandlers0Command(ASender: TIdCommand); var myData: TStrings; begi

我试图将数据库记录从服务器端应用程序传递到客户端应用程序。在客户端,我需要将数据存储到
TStrings
集合中

当我传递一个多行字段时,我在客户端收到两个独立的数据项,而不是一个多行数据项!我也尝试使用基于Unicode UTF8的命令来实现这一点,但不幸的是结果是一样的

服务器端代码:

procedure TForm1.IdCmdTCPServer1CommandHandlers0Command(ASender: TIdCommand);
var
  myData: TStrings;
begin
  myData := TStringList.Create;

  myData.Add('12'); // ID
  myData.Add('This is a multi line' + #13#10 + 'description.'); // Descriptions
  myData.Add('Thom Smith'); // Name

  try
    ASender.Context.Connection.Socket.Write(myData, True{, TIdTextEncoding.UTF8});
  finally
    myData.Free;
  end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
  myData: TStrings;
begin
  with TIdTCPClient.Create(nil) do
  begin
    Port := 1717;
    Host := 'localhost';

    try
      Connect;
      //IOHandler.DefStringEncoding := TIdTextEncoding.UTF8;

      myData := TStringList.Create;
      try
        SendCmd('greating');
        Socket.ReadStrings(myData, -1{, TIdTextEncoding.UTF8});

        eID.Text    := myData[0];  // ID TEdit
        mDes.Text   := myData[1];  // Descriptions TMemo
        eTelNo.Text := myData[2];  // Name TEdit
      finally
        myData.Free;
      end;
    finally
      Disconnect;
      Free;
    end;
  end;
end;
myData
服务器端的调试时间值为:

myData[0] = '12'
myData[1] = 'This is a multi line'#$D#$A'description.'
myData[2] = 'Thom Smith'
客户端代码:

procedure TForm1.IdCmdTCPServer1CommandHandlers0Command(ASender: TIdCommand);
var
  myData: TStrings;
begin
  myData := TStringList.Create;

  myData.Add('12'); // ID
  myData.Add('This is a multi line' + #13#10 + 'description.'); // Descriptions
  myData.Add('Thom Smith'); // Name

  try
    ASender.Context.Connection.Socket.Write(myData, True{, TIdTextEncoding.UTF8});
  finally
    myData.Free;
  end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
  myData: TStrings;
begin
  with TIdTCPClient.Create(nil) do
  begin
    Port := 1717;
    Host := 'localhost';

    try
      Connect;
      //IOHandler.DefStringEncoding := TIdTextEncoding.UTF8;

      myData := TStringList.Create;
      try
        SendCmd('greating');
        Socket.ReadStrings(myData, -1{, TIdTextEncoding.UTF8});

        eID.Text    := myData[0];  // ID TEdit
        mDes.Text   := myData[1];  // Descriptions TMemo
        eTelNo.Text := myData[2];  // Name TEdit
      finally
        myData.Free;
      end;
    finally
      Disconnect;
      Free;
    end;
  end;
end;
myData
客户端调试时间值:

myData[0]=“12” myData='这是一个多行' myData[2]=“说明。”

Telnet结果:

实际上,
myData[2]
应该保留的
'Thom Smith'
被替换为Description字段的第二行!
myData[2]
之后没有项目<代码>我的数据[3]不再可访问

我认为这个问题与Indy的
Write
ReadStrings
过程有关,因为它将ItemCount发送为3,但它发送两个项目(一个正确,下一个是两个项目!)

如何将回车符传递到另一侧,而不使
Write
过程中断
myData[1]
分成两行


非常感谢。

不要使用
t字符串
重载,因为它似乎将换行符用作字符串之间的分隔符,如果字符串本身包含换行符,则该分隔符不起作用

您可以轻松地编写自己的包装器方法,通过线路发送字符串列表(将其视为伪代码):


如果你想
TStrings.Text
忘记特殊字符,你应该在通过网络发送之前转义它们,然后取消转义。逃跑的方法有很多,所以选择一种适合你的方法

function EscapeString:(String): String --- your choice
function DeEscapeString:(String): String --- your choice

procedure SendEscapedStrings(const socket: TIdSocket; const data: TStrings);
var s: string; temp: TStringList;
begin
  temp := TStringList.Create;
  try
    temp.Capacity := data.Count;
    for s in data do
        temp.Add( EscapeString( s ) );
    socket.Write(temp);
  finally
    temp.Destroy;
  end;
end;

procedure ReadDeescapedStrings(const socket: TIdSocket; const data: TStrings);
var s: string; temp: TStringList;
begin
  temp := TStringList.Create;
  try
    Socket.ReadStrings(temp, -1);
    data.Clear;
    data.Capacity := temp.Count;
    for s in temp do
        temp.Add( DeEscapeString( s ) );
  finally
    temp.Destroy;
  end;
end;
现在的问题是,对于
DeEscapeString
EscapeString
,您会选择什么?选择很多

  • 您可以选择在发送前将字符串转换为base64,在读取后从base64转换字符串
  • 您可以选择用于转义的UUENCODE和用于反转义的UUENCODE
  • 您可以选择yEnc:
  • 或者你可以从
    JclString
    中选择非常简单的函数
    StrStringToEscaped
    strescapedtoestring
    从绝地代码库()中选择一个单位:

什么样的逃跑

如果您要求建议,我建议不要使用原始TCP服务器。有著名的标准HTTP协议,有许多用于Delphi实现HTTP服务器和HTTP客户端的库。在协议(和库)中,已经决定了一些事情,比如加密、压缩、语言支持等。如果出现问题,您可以使用任何HTTP嗅探器,用自己的眼睛查看谁出了问题—clent或服务器。调试要简单得多

如果您刚刚开始,我建议您研究HTTP+JSON Synopse mORMot库,也许它可以满足您的需求。例如,您可以从库中的演示中获取示例服务器代码

然后,若要安排原始TCP服务器,我会发送压缩数据,这样它会工作得更好(网络通常比CPU慢)。看

发送:

  • 1:发送到网络(int32)-TStringList.Count
  • 2:每做一根弦
  • 2.1从字符串[i]创建
    TStringStream
  • 2.2通过TZCompressionStream传递
  • 2.3发送(int32)压缩数据的大小
  • 2.4发送数据本身
  • 2.5释放临时溪流
接收

  • 1:从网络接收(int32)-数据包计数
  • 1.1结果晶莹剔透;ResultStringList.Capacity:=读取计数
  • 2:每做一根弦
  • 2.1创建
    tbytestream
  • 2.2从网络读取(int32)压缩数据的大小
  • 2.3将N个字节从网络读入BytesStream
  • 2.4通过TZDecompressionStream将其解包至TStringStream
  • 2.5结果字符串.添加(字符串流->字符串)
  • 2.6释放临时溪流

现在,如果你真的不想改变任何事情,那么JCL转义对你来说就足够了。至少它对我有效,但我的任务非常不同,与网络无关。但是你可以测试它们,看看它是如何工作的。

ReadString()
需要一个字节长度作为输入,但你没有指定一个。@Remy:我没有可用的Delphi…这就是为什么我明确提到这是伪代码。@jpfollenius:我在Stackoverflow中问这个问题之前尝试过这个方法。但问题就在这里,
ReadString()
需要发送字符串的长度,而我的发送字符串长度是可变的。@FarshadH。那么在字符串本身之前发送字符串的长度,有什么问题吗?@FarshadH。标准方法是电子邮件/NNTP或HTTP或XMPP(这些标准的一部分是标准编码方法,这是标准方法的唯一定义)。他们多年来一直在努力解决这些问题,并且拥有许多用于测试/调试的工具。甚至只是在服务器上运行压力测试。任何你自己的协议都不是标准的。特别是如果您想为您的服务器开发一个移动客户端,然后使用公共标准确保您拥有世界上所有的工具可供选择,而不是从二进制级别(包括字节顺序)重新实现您自己的协议。谢谢您的建议。我需要发送Unicode字符串。您建议使用哪种类型的转义?@FarshadH-ZStream(),因此它将被压缩。从上面的选项-只要尝试所有的选项,看看会脚你。我最近使用了JCL选项,它非常愚蠢,但很有效,至少在我的例子中是这样。