简体   繁体   English

Delphi TidTCPServer和TidTCPClient传输记录

[英]Delphi TidTCPServer and TidTCPClient transferring a record

I need help in understanding how to transfer a record through Indy TCP Server/Client. 我需要帮助来了解如何通过Indy TCP服务器/客户端传输记录。 I have 2 programs, in I put client and in another server. 我有2个程序,我把客户端和另一个服务器。 On client on a button I put connect : Client is TIdTCPClient 在客户端上我按下了一个按钮:客户端是TIdTCPClient

Client.Connect();

And at server side I am adding a line to memo that client is connected , on ServerConnect event 在服务器端,我在ServerConnect事件上添加一行到客户端连接的备忘录

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

To send data from client I have a record, which I want to send : 要从客户端发送数据,我有一条记录,我想发送:

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

And I have a send button there : 我在那里有一个发送按钮:

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;

At server side onexecute I have the following code , I have same tmyrecord declared at server side too : 在服务器端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

I dont know why it is not working, why I cant show IP adress which I wrote from client side. 我不知道为什么它不起作用,为什么我不能显示我从客户端写的IP地址。 I want to read a record (msRecInfo) on server side which I am sending from client side. 我想读取服务器端的记录(msRecInfo),我从客户端发送。 I want to access my record elements, in this case I want to read IPSTR element of my record. 我想访问我的记录元素,在这种情况下我想读取记录的IPSTR元素。 When I press send button from a client side, application hangs, server part. 当我从客户端按下发送按钮时,应用程序挂起,服务器部分。

Thanks a lot in advance 非常感谢提前

You are making a classic newbie mistake - you are expecting the default behaviors of the TIdIOHandler.Write(TStream) and TIdIOHandler.ReadStream() methods to match each other, but they actually do not. 您正在犯一个经典的新手错误 - 您期望TIdIOHandler.Write(TStream)TIdIOHandler.ReadStream()方法的默认行为相互匹配,但它们实际上并不相同。

The default parameter values of TIdIOHandler.ReadStream() tell it to expect an Integer or Int64 (depending on the value of the TIdIOHandler.LargeStream property) to preceed the stream data to specify the length of the data. TIdIOHandler.ReadStream()的默认参数值告诉它期望IntegerInt64 (取决于TIdIOHandler.LargeStream属性的值)在流数据之前指定数据的长度。

However, the default parameter values of TIdIOHandler.Write(TStream) do not tell it to send any such Integer/Int64 value. 但是, TIdIOHandler.Write(TStream)的默认参数值不会告诉它发送任何此类Integer/Int64值。 Thus, your use of TIdIOHandler.ReadStream() reads the first few bytes of the record and interprets them as an Integer/Int64 (which is 926036233 given the string value you are sending), and then waits for that many bytes to arrive, which never will so TIdIOHandler.ReadStream() does not exit (unless you set the TIdIOHandler.ReadTimeout property to a non-infinite value). 因此,您使用TIdIOHandler.ReadStream()读取记录的前几个字节并将它们解释为Integer/Int64 (给定您发送的字符串值为926036233 ),然后等待那么多字节到达,从来没有这样TIdIOHandler.ReadStream()不会退出(除非您将TIdIOHandler.ReadTimeout属性设置为非无限值)。

There are also some other minor bugs/typos in your code that uses the TMemoryStream objects outside of Indy. 您的代码中还有一些其他小错误/拼写错误,它们使用Indy之外的TMemoryStream对象。

Try this instead: 试试这个:

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;

Or this: 或这个:

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; 

Alternatively, you can send the record using TIdBytes instead of TStream : 或者,您可以使用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; 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM