IndyTCP delphi对象交换数组

IndyTCP delphi对象交换数组,delphi,serialization,tcp,memorystream,Delphi,Serialization,Tcp,Memorystream,很抱歉,我知道我问的问题太多了,但明天(实际上是今天,因为在我的国家现在是凌晨2点),我需要向我的老师展示我开始制作e.t.c.的内容。因此,正如我在前面的问题中所问的,我需要从服务器向客户端发送一些数据。 但是,在tmemo1.Lines.Add(IntToStr(arrOf[1]))之后,服务器的memo字段中不会出现任何内容 我试着在客户机上这样发送 procedure TForm1.btnTestClick(Sender: TObject); var msRecInfo: TMemo

很抱歉,我知道我问的问题太多了,但明天(实际上是今天,因为在我的国家现在是凌晨2点),我需要向我的老师展示我开始制作e.t.c.的内容。因此,正如我在前面的问题中所问的,我需要从服务器向客户端发送一些数据。 但是,在t
memo1.Lines.Add(IntToStr(arrOf[1]))之后,服务器的memo字段中不会出现任何内容

我试着在客户机上这样发送

procedure TForm1.btnTestClick(Sender: TObject);
var
  msRecInfo: TMemoryStream;
  arrOf: array of integer; i:integer;
begin
  setLength(arrOf, 11);
  for i := 0 to 10 do
    arrOf[i]:=random(100);

  msRecInfo:= TMemoryStream.Create;

  try
    msRecInfo.Write(arrOf, SizeOf(arrOf));
    idTCPClient1.IOHandler.Write(msRecInfo);
  finally
     msRecInfo.Free;
  end;

end;
在服务器上

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
   msRecInfo: TMemoryStream;
  arrOf: array of Integer; i:integer;
begin
  msRecInfo:= TMemoryStream.Create;
  try
    AContext.Connection.IOHandler.ReadStream(msRecInfo, -1, False);
    SetLength(arrOf,11);
    msRecInfo.Position := 0;
    msRecInfo.Read(arrOf, SizeOf(arrof));
  finally
    memo1.Lines.Add(IntToStr(arrOf[1]));
    msRecInfo.Free;
  end;    
end;

请您帮助我解决这个问题,并找到一些如何发送不同类型/类的数组的示例

这是您的主要问题

msRecInfo.Write( arrOf, SizeOf( arrOf ) );
将数组的指针地址写入流中。。。我不认为那是你的目标

如果要将数组的内容放入流中,则应使用

msRecInfo.Write( arrOf[ Low( arrOf ) ], SizeOf( Integer ) * Length( arrOf ) );
为什么??您必须指向数据的第一个位置(数组的第一个元素),并且必须计算数据的长度

在接收端,它是一样的

msRecInfo.Read( arrOf[ Low( arrOf ) ], SizeOf( Integer ) * Length( arrOf ) );

PS:在这种特殊情况下,这可能很有效,但为了安全起见,您应该首先发送所有数据的长度,以便接收者知道消息何时完成这是您的主要问题

msRecInfo.Write( arrOf, SizeOf( arrOf ) );
将数组的指针地址写入流中。。。我不认为那是你的目标

如果要将数组的内容放入流中,则应使用

msRecInfo.Write( arrOf[ Low( arrOf ) ], SizeOf( Integer ) * Length( arrOf ) );
为什么??您必须指向数据的第一个位置(数组的第一个元素),并且必须计算数据的长度

在接收端,它是一样的

msRecInfo.Read( arrOf[ Low( arrOf ) ], SizeOf( Integer ) * Length( arrOf ) );

PS:在这种特殊情况下,这可能会很好地工作,但为了安全起见,您应该首先发送所有数据的长度,以便接收方知道,当消息完成时

,正如Rufo已经解释的,您没有正确地将数组写入
TMemoryStream
并从中读取数组

更糟糕的是,您也没有正确地通过套接字发送
TMemoryStream
TIdIOHandler.Write(TStream)
TIdIOHandler.ReadStream()
的默认参数彼此不兼容。默认情况下,
Write(TStream)
不发送
TStream.Size
值。但是,
ReadStream()
的默认参数(与您明确传递的值相同)告诉它读取前几个字节,并将它们解释为
大小,在本例中这是非常错误的

请尝试以下方法:

procedure TForm1.btnTestClick(Sender: TObject);
var
  msRecInfo: TMemoryStream;
  arrOf: Array of Integer;
  i: Integer;
begin
  SetLength(arrOf, 11);
  for i := Low(arrOf) to High(arrOf) do
    arrOf[i] := random(100);

  msRecInfo := TMemoryStream.Create;
  try
    msRecInfo.WriteBuffer(arrOf[0], Length(arrOf) * SizeOf(Integer));
    IdTCPClient1.IOHandler.Write(msRecInfo, 0, True);
  finally
     msRecInfo.Free;
  end;
end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  msRecInfo: TMemoryStream;
  arrOf: Array of Integer;
  i: Integer;
begin
  msRecInfo := TMemoryStream.Create;
  try
    AContext.Connection.IOHandler.ReadStream(msRecInfo, -1, False);
    SetLength(arrOf, msRecInfo.Size div SizeOf(Integer));
    if Lenth(arrOf) > 0 then
    begin
      msRecInfo.Position := 0;
      msRecInfo.ReadBuffer(arrOf[0], Length(arrOf) * SizeOf(Integer));
    end;
  finally
    msRecInfo.Free;
  end;    
  ...
end;
或者,去掉
TMemoryStream
,并自行发送单个
整数
值:

procedure TForm1.btnTestClick(Sender: TObject);
var
  arrOf: Array of Integer;
  i: Integer;
begin
  SetLength(arrOf, 11);
  for i := Low(arrOf) to High(arrOf) do
    arrOf[i] := random(100);

  IdTCPClient1.IOHandler.Write(Length(arrOf));
  for I := Low(arrOf) to High(arrOf) do
    IdTCPClient1.IOHandler.Write(arrOf[i]);
end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  arrOf: Array of Integer;
  i: Integer;
begin
  i := AContext.Connection.IOHandler.ReadLongInt;
  SetLength(arrOf, i);
  for i := Low(arrOf) to High(arrOf) do
    arrOf[i] := AContext.Connection.IOHandler.ReadLongInt;
  ...
end;
现在,尽管如此,直接在
OnExecute
事件处理程序中访问
TMemo
不是线程安全的
TIdTCPServer
是一个多线程组件。
OnExecute
事件是在工作线程而不是主线程的上下文中触发的。UI组件,如
TMemo
,无法从主线程外部安全访问。您可以使用Indy的
TIdNotify
TIdSync
类与主线程同步,例如:

type
  TMemoSync = class(TIdSync)
  protected
    FLine: String;
    procedure DoSynchronize; override;
  end;

procedure TMemoSync.DoSynchronize;
begin
  Form1.Memo1.Lines.Add(FLine);
end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  ...
begin
  ...
  with TMemoSync.Create do try
    FLine := IntToStr(arrOf[1]);
    Synchronize;
  finally
    Free;
  end;
  ...
end;

如果不与主线程同步,可能会发生不好的事情。

正如Rufo已经解释的那样,您没有正确地将数组写入
TMemoryStream中,也没有正确地从
TMemoryStream中读取数组

更糟糕的是,您也没有正确地通过套接字发送
TMemoryStream
TIdIOHandler.Write(TStream)
TIdIOHandler.ReadStream()
的默认参数彼此不兼容。默认情况下,
Write(TStream)
不发送
TStream.Size
值。但是,
ReadStream()
的默认参数(与您明确传递的值相同)告诉它读取前几个字节,并将它们解释为
大小,在本例中这是非常错误的

请尝试以下方法:

procedure TForm1.btnTestClick(Sender: TObject);
var
  msRecInfo: TMemoryStream;
  arrOf: Array of Integer;
  i: Integer;
begin
  SetLength(arrOf, 11);
  for i := Low(arrOf) to High(arrOf) do
    arrOf[i] := random(100);

  msRecInfo := TMemoryStream.Create;
  try
    msRecInfo.WriteBuffer(arrOf[0], Length(arrOf) * SizeOf(Integer));
    IdTCPClient1.IOHandler.Write(msRecInfo, 0, True);
  finally
     msRecInfo.Free;
  end;
end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  msRecInfo: TMemoryStream;
  arrOf: Array of Integer;
  i: Integer;
begin
  msRecInfo := TMemoryStream.Create;
  try
    AContext.Connection.IOHandler.ReadStream(msRecInfo, -1, False);
    SetLength(arrOf, msRecInfo.Size div SizeOf(Integer));
    if Lenth(arrOf) > 0 then
    begin
      msRecInfo.Position := 0;
      msRecInfo.ReadBuffer(arrOf[0], Length(arrOf) * SizeOf(Integer));
    end;
  finally
    msRecInfo.Free;
  end;    
  ...
end;
或者,去掉
TMemoryStream
,并自行发送单个
整数
值:

procedure TForm1.btnTestClick(Sender: TObject);
var
  arrOf: Array of Integer;
  i: Integer;
begin
  SetLength(arrOf, 11);
  for i := Low(arrOf) to High(arrOf) do
    arrOf[i] := random(100);

  IdTCPClient1.IOHandler.Write(Length(arrOf));
  for I := Low(arrOf) to High(arrOf) do
    IdTCPClient1.IOHandler.Write(arrOf[i]);
end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  arrOf: Array of Integer;
  i: Integer;
begin
  i := AContext.Connection.IOHandler.ReadLongInt;
  SetLength(arrOf, i);
  for i := Low(arrOf) to High(arrOf) do
    arrOf[i] := AContext.Connection.IOHandler.ReadLongInt;
  ...
end;
现在,尽管如此,直接在
OnExecute
事件处理程序中访问
TMemo
不是线程安全的
TIdTCPServer
是一个多线程组件。
OnExecute
事件是在工作线程而不是主线程的上下文中触发的。UI组件,如
TMemo
,无法从主线程外部安全访问。您可以使用Indy的
TIdNotify
TIdSync
类与主线程同步,例如:

type
  TMemoSync = class(TIdSync)
  protected
    FLine: String;
    procedure DoSynchronize; override;
  end;

procedure TMemoSync.DoSynchronize;
begin
  Form1.Memo1.Lines.Add(FLine);
end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  ...
begin
  ...
  with TMemoSync.Create do try
    FLine := IntToStr(arrOf[1]);
    Synchronize;
  finally
    Free;
  end;
  ...
end;

如果您不与主线程同步,可能会发生不好的事情。

这是让您开始的事情吗?,。您是否检查过(例如调试器)SizeOf(arrOf)的结果是否与您预期的相同?@LURD完全不是我需要的事情,但谢谢您没有将客户端和服务器混合在一起up@DavidHeffernan对不起,现在我编辑这篇文章是为了让你开始吗?,。你有没有检查过(例如调试器)SizeOf(arrOf)的结果是否与你预期的相同?@LURD不是我需要的东西,但谢谢你,你的客户端和服务器不是混合了吗up@DavidHeffernan对不起,现在我编辑了。你用调试器检查过了吗?或者尝试memo1.Lines.Add(IntToStr(msRecInfo.Size));只是想看看,收到了多少字节。。。如果我真的不知道如何在客户机-服务器交换期间使用调试器。但是我像你说的那样生气
memo1.Lines.Add(IntToStr(msRecInfo.Size))仍然没有任何内容。嗯,那你觉得呢。。。服务器从未获取数据或事件未连接到组件,您必须检查在
过程TForm1.IdTCPServer1Execute(AContext:TIdContext)中添加的代码i
memo1.Lines.Add('Test')并且它在客户端连接到服务器后工作。我是说,这表明它是相互联系的,y