7

我需要帮助来了解如何通过 Indy TCP Server/Client 传输记录。我有 2 个程序,在我放置客户端和在另一台服务器中。在客户端上的按钮上我放置连接:客户端是 TIdTCPClient

Client.Connect();

在服务器端,我在 ServerConnect 事件中添加了一条客户端已连接的备忘录

Protocol.Lines.Add(TimeToStr(Time)+' connected ');

要从客户端发送数据,我有一条记录,我想发送:

Tmyrecord = record
IPStr: string[15];
end;

我有一个发送按钮:

procedure Tform1.ButtonSendClick(Sender: TObject);
  var
  MIRec: Tmyrecord;
 msRecInfo: TMemoryStream;
 begin
   MIRec.IPStr := '172.0.0.1';
   msRecInfo := TMemoryStream.Create;
   msRecInfo.Write(MIRec, SizeOf(MIRec));
    msRecInfo.Position := 0;
   Client.IOHandler.Write(msRecInfo);
 end;

在服务器端 onexecute 我有以下代码,我在服务器端也声明了相同的 tmyrecord :

 procedure TServerFrmMain.ServerExecute(AContext: TIdContext);
 var
  MIRec: Tmyrecord;
  msRecInfo: TMemoryStream;
 begin
 if  AContext.Connection.Connected then
  begin
    AContext.Connection.IOHandler.CheckForDataOnSource(10);
    if not AContext.Connection.IOHandler.InputBufferIsEmpty then
   begin
     msRecInfo:= TMemoryStream.Create;
       AContext.Connection.IOHandler.ReadStream(msRecInfo);
     msRecInfo.Read(MIRec, sizeOf(msRecInfo));
    ShowMessage(MIRec.IPStr);
 end;
 end;
 end

我不知道为什么它不起作用,为什么我不能显示我从客户端写的 IP 地址。我想在服务器端读取我从客户端发送的记录(msRecInfo)。我想访问我的记录元素,在这种情况下,我想读取记录的 IPSTR 元素。当我从客户端按下发送按钮时,应用程序挂起,服务器部分。

非常感谢提前

4

1 回答 1

11

你犯了一个典型的新手错误——你期望TIdIOHandler.Write(TStream)TIdIOHandler.ReadStream()方法的默认行为相互匹配,但实际上它们并不匹配。

的默认参数值TIdIOHandler.ReadStream()告诉它期望一个IntegerInt64(取决于TIdIOHandler.LargeStream属性的值)在流数据之前指定数据的长度。

但是,默认参数值TIdIOHandler.Write(TStream)不会告诉它发送任何此类Integer/Int64值。因此,您使用TIdIOHandler.ReadStream()读取记录的前几个字节并将它们解释为Integer/Int64926036233给定您要发送的字符串值),然后等待那么多字节到达,这永远不会因此TIdIOHandler.ReadStream()不会退出(除非您将TIdIOHandler.ReadTimeout属性设置为非无限值)。

您的代码中还有一些其他小错误/错别字使用了TMemoryStreamIndy 之外的对象。

试试这个:

procedure Tform1.ButtonSendClick(Sender: TObject); 
var 
  MIRec: Tmyrecord; 
  msRecInfo: TMemoryStream; 
begin 
  MIRec.IPStr := '172.0.0.1'; 
  msRecInfo := TMemoryStream.Create; 
  try
    msRecInfo.Write(MIRec, SizeOf(MIRec)); 

    // writes the stream size then writes the stream data
    Client.IOHandler.Write(msRecInfo, 0, True);
  finally
    msRecInfo.Free;
  end;
end; 

procedure TServerFrmMain.ServerExecute(AContext: TIdContext); 
var 
  MIRec: Tmyrecord; 
  msRecInfo: TMemoryStream; 
begin 
  msRecInfo := TMemoryStream.Create; 
  try
    // reads the stream size then reads the stream data
    AContext.Connection.IOHandler.ReadStream(msRecInfo, -1, False);

    msRecInfo.Position := 0;
    msRecInfo.Read(MIRec, SizeOf(MIRec)); 
    ...
  finally
    msRecInfo.Free;
  end;
end;

或这个:

procedure Tform1.ButtonSendClick(Sender: TObject); 
var 
  MIRec: Tmyrecord; 
  msRecInfo: TMemoryStream; 
begin 
  MIRec.IPStr := '172.0.0.1'; 
  msRecInfo := TMemoryStream.Create; 
  try
    msRecInfo.Write(MIRec, SizeOf(MIRec)); 

    // does not write the stream size, just the stream data
    Client.IOHandler.Write(msRecInfo, 0, False); 
  finally
    msRecInfo.Free;
  end;
end; 

procedure TServerFrmMain.ServerExecute(AContext: TIdContext); 
var 
  MIRec: Tmyrecord; 
  msRecInfo: TMemoryStream; 
begin 
  msRecInfo := TMemoryStream.Create; 
  try
    // does not read the stream size, just the stream data
    AContext.Connection.IOHandler.ReadStream(msRecInfo, SizeOf(MIRec), False); 

    msRecInfo.Position := 0;
    msRecInfo.Read(MIRec, SizeOf(MIRec)); 
    ...
  finally
    msRecInfo.Free;
  end; 
end; 

或者,您可以使用TIdBytes而不是发送记录TStream

procedure Tform1.ButtonSendClick(Sender: TObject); 
var 
  MIRec: Tmyrecord; 
  Buffer: TIdBytes;
begin 
  MIRec.IPStr := '172.0.0.1'; 
  Buffer := RawToBytes(MIRec, SizeOf(MIRec));
  Client.IOHandler.Write(Buffer); 
end; 

procedure TServerFrmMain.ServerExecute(AContext: TIdContext); 
var 
  MIRec: Tmyrecord; 
  Buffer: TIdBytes; 
begin 
  AContext.Connection.IOHandler.ReadBytes(Buffer, SizeOf(MIRec)); 
  BytesToRaw(Buffer, MIRec, SizeOf(MIRec));
  ...
end; 
于 2012-06-05T00:30:56.490 回答