对不起,我知道我问了太多问题,但是明天(实际上今天是因为我现在已经是凌晨2点了)我需要向老师展示我开始做什么e.t.c.因此,在我之前的问题中,我需要从服务器向客户端发送一些数据。
但是在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;
请帮助我解决这个问题并找到一些如何发送不同类型/类数组的示例?
答案 0 :(得分: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:这在这种特殊情况下可能效果很好,但为了安全起见,您应首先发送所有数据的长度,以便接收方知道,何时消息完成
答案 1 :(得分: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的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;
如果你不与主线程同步,可能会发生不好的事情。