2014-01-20 21 views
0

我试图将数据库记录从服务器端应用程序传递到我的客户端应用程序。在客户端,我需要将我的数据存储到TStrings集合中。如何将TIdTCPServer的多线串行数据传递给TIdTCPClient

当我传递多行字段时,我在客户端接收两个单独的数据项,而不是一个多行数据项!我也尝试过使用基于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; 

myData服务器端的调试时间值:

myData[0] = '12' 
myData[1] = 'This is a multi line'#$D#$A'description.' 
myData[2] = 'Thom Smith' 

客户端代码:

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 ='这是多行' myData [2] ='description。'

的Telnet结果:

enter image description here

其实,myData[2]应该保持'Thom Smith'与描述字段的第二行更换!并且在myData[2]之后没有任何项目。 myData[3]无法访问。

我想这个问题是关系到Indy的WriteReadStrings程序,因为它发出ItemCount中为3,但它发出两个项目(一个正确的,接下来的喙两个项目!)。

如何将回车符传递给对方,而不将Write程序中断myData[1]分为两行?

非常感谢。

回答

2

- 之前,您应该逃避他们:

您可以轻松编写自己的包装方法,通过网络发送的字符串列表(把它看作是伪代码)通过网络发送,并在此之后解除。有很多逃避方法,所以选一个适合你的方法。

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; 

现在的问题是你会选择DeEscapeStringEscapeString?选项很多。

  • 您可以选择转换字符串发送之前和BASE64为Base64阅读
  • 后,您可以选择UUEEncode为escapgin和UUEDecode的去逃避
  • 您可以选择yEnc:http://en.wikipedia.org/wiki/YEnc
  • 或者你可以选择非常简单的功能StrStringToEscaped和从绝CodeLib StrEscapedToStringJclString单元(http://jcl.sf.net):

什么样的逃逸

如果你问我的建议将不会使用原始的TCP服务器提示的。有众所周知的标准HTTP协议,Delphi中有许多库实现HTTP服务器和HTTP客户端。而在协议(和库)中,已经决定了诸如加密,压缩,语言支持等等。如果某个错误出现了问题 - 您可以使用任何HTTP嗅探器并查看错误或服务器中的错误 - 使用您自己的眼睛。调试更简单。

如果你刚开始,我建议你看看HTTP + JSON Synopse mORMot库,也许它会覆盖你的需求。例如,您可以从http://robertocschneiders.wordpress.com/2012/11/22/datasnap-analysis-based-on-speed-stability-tests/中获取示例服务器代码,或者从lib中的演示中获取示例服务器代码。然后,如果围绕原始TCP服务器,我会发送压缩数据,所以它会更好地工作(网络比CPU通常慢)。见http://docwiki.embarcadero.com/CodeExamples/XE5/en/ZLibCompressDecompress_(Delphi)

发送:

  • 1:发送到网络(INT32) - TStringList.Count
  • 2:每串做
  • 2.1从字符串生成TStringStream [I]
  • 2.2合格它通过TZCompressionStream
  • 2.3发送(int32)压缩数据的大小
  • 2.4发送数据本身
  • 2.5释放临时流

接收

  • 1:从净接收(INT32) - 包
  • 1.1 ResultStringList.Clear的计数; ResultStringList.Capacity:= read_count。
  • 2:每串做
  • 2.1创建TBytesStream
  • 2.2从净(INT32)读取压缩的数据
  • 的大小
  • 2.3从网络上读取N个字节到BytesStream
  • 2.4经由TZDecompressionStream它解成TStringStream
  • 2.5 ResultStringList。Add(StringStream - > string);
  • 2.6释放临时流

现在,如果你真的不想改变加时赛几乎所有的东西,然后逃离JCL将有望够你。至少它对我有用,但我的任务是非常不同的,并不是关于网络。但是你可以测试它们,看看它是如何工作的。

+0

感谢您的建议,我需要发送Unicode字符串,您建议什么样的转义? –

+1

@FarshadH - ZStream( http://docwiki.embarcadero.com/CodeExamples/XE5/en/ZLibCompressDecompress_(Delphi)),所以它会被压缩。从上面的选项 - 只是尝试所有的选项,看看会脚你。我最近使用了JCL选项,但它非常愚蠢,但至少在我的情况下工作。 –

+0

非常有用,非常感谢... –

0

不要使用TStrings重载,因为它似乎使用换行符作为字符串之间的分隔符,如果字符串本身包含换行符,则不起作用。如果你想TStrings.Text是无视特殊字符

procedure WriteStrings(IOHandler : TIdIOHandler; Strings : TStrings); 
var 
    Str : String; 
begin 
IOHandler.WriteBufferOpen; 
try 
    IOHandler.Write(Strings.Count); 
    for Str in Strings do 
    IOHandler.Write(Str); 
finally 
    IOHandler.WriteBufferClose; 
end; 
end; 

procedure ReadStrings(IOHandler : TIdIOHandler; Strings : TStrings); 
var 
    Count, I : Integer; 
begin 
Count := IOHandler.ReadInteger; 
for I := 1 to Count do 
    Strings.Add(IOHandler.ReadString); 
end; 
+1

'ReadString()'需要一个字节长度作为输入,但你没有指定一个。 –

+0

@雷米:我没有德尔福可用...这就是为什么我明确提到这是伪代码。 – jpfollenius

+0

@jpfollenius:在我在Stackoverflow中问这个问题之前,我尝试了这种方法。但问题恰恰在于'ReadString()'需要发送字符串的长度,并且我发送的字符串长度是可变的。 –