0

对不起,我知道我问了太多问题,但是明天(实际上是今天,因为在我的国家,现在是凌晨 2:00)我需要向我的老师展示我开始制作的东西等等所以正如我在之前的问题中所问的我需要从服务器向客户端发送一些数据。但是在那之后服务器的备忘录字段中什么也没有出现memo1.Lines.Add(IntToStr(arrOf[1]));

我试图在客户端发送它

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;

请你能帮我解决这个问题并找到一些如何发送不同类型/类的数组的例子吗?

4

2 回答 2

3

这是您的主要问题

msRecInfo.Write( arrOf, SizeOf( arrOf ) );

您将数组的指针地址写入流中……我不认为那是您的目标。

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

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

为什么?您必须指向数据的第一个位置(数组的第一个元素),并且您必须计算数据的长度。

在接收部分它是一样的

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

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

于 2012-11-21T23:20:47.167 回答
3

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

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

试试这个:

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并自己发送单个Integer值:

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;

现在,话虽如此,TMemo直接在OnExecute事件处理程序中访问不是线程安全的。 TIdTCPServer是一个多线程组件。该OnExecute事件在工作线程的上下文中触发,而不是在主线程中触发。UI 组件,如TMemo,不能从主线程外部安全地访问。您可以使用 Indy 的TIdNotifyTIdSync类与主线程同步,例如:

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;

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

于 2012-11-22T00:15:32.080 回答