Indy10和iDTCPServer和idTCPClient丢失的数据

问题描述 投票:0回答:1

我有两个使用Delphy 10.3和Indy 10 idTCPServer和idTCPClient0的程序:

服务器端:

  • 服务器使用计时器定期发送TIDBytes的数据集1(150字节的数据)
  • 服务器发送TIDBytes的数据集2,但仅不时发送
  • 服务器使用TIDServer.Connection.IOHandler.Write(IDBytesArray);发送数据;

客户端:

  • 客户端如许多示例中所述通过线程接收TIDBytes

问题

  • 如果服务器的计时器确实发送了低频数据(1000毫秒),那么一切正常,客户端将接收到这两个数据集(一个来自服务器计时器,另一个经常发送)。
  • 但是,如果服务器的计时器以高频率(每50毫秒)发送数据集1,则不能接收到第二个数据集中的所有数据(但正在接收计时器发送的所有数据)。

问题-这可能是缓冲区问题吗?还是计时器会覆盖已经在缓冲区中但尚未由客户端读取的数据集2?我有什么办法可以克服这种情况?

delphi buffer tcpclient indy tcpserver
1个回答
0
投票
Lebeau确实感谢您的答复。我认为您正确地提到了一个计时器可以将数据发送到端口,这可能会使另一个计时器混乱,该计时器也同时将数据写入端口。因此,我简化了示例:

    客户端定期将Data1结构的记录作为tidBytes发送到服务器。
  • 服务器以确认响应。
  • 客户端检查确认是否属于最后发送的数据集。
  • 只要客户端发送包的速度不超过每100毫秒],此方法就可以正常工作。如果发送说aevry 10 millisec,则客户端的某些确认会丢失。如果有帮助,我可以共享整个演示项目。但这可能不是堆栈溢出的原因。所以我在下面添加一些代码:
  • 定义了两个数据记录:-TData1是从客户端发送到服务器的TData1。-服务器将TAcknowledgeData1作为确认发送回客户端]

    type TData1 = record // 11 bytes record {header:} MessageStart : Array[1..4] of Char; // 0 MessageID : word; // 4 {content:} TransactionNo : Integer; // 6 TrackerMsgID : byte; // 10 end; type TAcknowledgeData1 = record // 14 bytes record {Header:} MessageStart : Array[1..4] of Char; // 0 MessageID : Word; // 4 {content:} TransactionNo : Integer; // 6 EventID : Integer; // 10 end;

客户端具有一个计时器,该计时器定期将Dataset1发送到服务器,并调用过程SendData1:

procedure TForm1.TimerClientTimer(Sender: TObject); begin SendData1(TransactionNr); TransactionNr := TransactionNr + 1; end; procedure TForm1.SendData1 (Transaction: Integer); var Data1 : TData1; Data1Array : TIDBytes; begin {fill the data1 record:} Data1.MessageStart := '$MSG'; //4 bytes Data1.MessageID := 1; //2 bytes Data1.TransactionNo:= Transaction; //4 bytes Data1.TrackerMsgID := 1; //1 byte {set the length of idBytes to get the dta 1 record:} setLength (Data1Array,11); {move data1 record to idBytes array:} Move (Data1.MessageStart[1],Data1Array[0],1); Move (Data1.MessageStart[2],Data1Array[1],1); Move (Data1.MessageStart[3],Data1Array[2],1); Move (Data1.MessageStart[4],Data1Array[3],1); Move(Data1.MessageID, Data1Array[4],sizeOf(Word)); Move(Data1.TransactionNo,Data1Array[6],sizeOf(Integer)); Move(Data1.TrackerMsgID, Data1Array[10],sizeOf(Byte)); try TCPClient.IOHandler.Write(Data1Array); if chkData.checked then MemoClient.Lines.Add('Client sent Data1:'+inttostr(Data1.TransactionNo)); except on E: Exception do begin {nothing} if chkData.checked then MemoClient.Lines.Add('Exception occured'); end; end; end;

一旦确认数据包从服务器到达,客户端的工作线程正在调用DataReceived:

procedure TForm1.TimerClientTimer(Sender: TObject); begin SendData1(TransactionNr); TransactionNr := TransactionNr + 1; end; procedure TForm1.SendData1 (Transaction: Integer); var Data1 : TData1; Data1Array : TIDBytes; begin {fill the data1 record:} Data1.MessageStart := '$MSG'; //4 bytes Data1.MessageID := 1; //2 bytes Data1.TransactionNo:= Transaction; //4 bytes Data1.TrackerMsgID := 1; //1 byte {set the length of idBytes to get the dta 1 record:} setLength (Data1Array,11); {move data1 record to idBytes array:} Move (Data1.MessageStart[1],Data1Array[0],1); Move (Data1.MessageStart[2],Data1Array[1],1); Move (Data1.MessageStart[3],Data1Array[2],1); Move (Data1.MessageStart[4],Data1Array[3],1); Move(Data1.MessageID, Data1Array[4],sizeOf(Word)); Move(Data1.TransactionNo,Data1Array[6],sizeOf(Integer)); Move(Data1.TrackerMsgID, Data1Array[10],sizeOf(Byte)); try TCPClient.IOHandler.Write(Data1Array); if chkData.checked then MemoClient.Lines.Add('Client sent Data1:'+inttostr(Data1.TransactionNo)); except on E: Exception do begin {nothing} if chkData.checked then MemoClient.Lines.Add('Exception occured'); end; end; end;

一旦服务器发送数据包,客户端的工作线程正在调用DataReceived:

procedure TForm1.Datareceived (Data : TidBytes); var MsgStart : array[1..4] of char; s : string; id : word; Data1: TData1; Data2: TData2; Ack : TAcknowledgeData1; AckArray: TidBytes; begin {get the header:} s := bytestostring(Data,0,4); if s = '' then exit; move (Data[4],id,sizeof(word)); if (s = '$MSG') then begin if (ID=3) then begin move(Data[0],Ack.MessageStart,0); Ack.MessageID := id; Move (Data[6],Ack.TransactionNo,SizeOf(Word)); Move (Data[10],Ack.EventID,SizeOf(Integer)); LastAck := Ack.TransactionNo; end; end; end;

服务器在客户端发送Data1程序包后立即调用DataReceved过程。服务器将确认包发送回客户端:

procedure TForm1.Datareceived (Data : TidBytes); var MsgStart : array[1..4] of char; s : string; id : word; Data1: TData1; Data2: TData2; Ack : TAcknowledgeData1; AckArray: TidBytes; begin {get the header:} s := bytestostring(Data,0,4); if s = '' then exit; move (Data[4],id,sizeof(word)); if (s = '$MSG') then begin {Server received Data1:} if (ID=1) then begin {get data1:} move(Data[0],Data1.MessageStart,0); Data1.MessageID := id; move (Data[6],Data1.TransactionNo,sizeOf(Integer)); move (Data[10],Data1.TrackerMsgID,sizeOf(Byte)); {send Acknowledge to client} Ack.MessageStart := '$MSG'; Ack.MessageID := 3; Ack.TransactionNo:= Data1.TransactionNo; Ack.EventID := LastEventID; LastEventID := LastEventID + 1; SetLength(AckArray,14); Move (Ack.MessageStart[1],AckArray[0],1); Move (Ack.MessageStart[2],AckArray[1],1); Move (Ack.MessageStart[3],AckArray[2],1); Move (Ack.MessageStart[4],AckArray[3],1); Move (Ack.MessageID,AckArray[4],sizeOf(Word)); Move (Ack.TransactionNo,AckArray[6],sizeOf(Integer)); Move (Ack.EventID,AckArray[10],sizeOf(Integer)); try ClientPortIdContext.Connection.IOHandler.Write(AckArray); except end; end;

© www.soinside.com 2019 - 2024. All rights reserved.